Предположим, у меня есть простой шаблонный класс:
template <typename ElementType, ElementType Element>
class ConsecutiveMatcher
{
public:
bool operator () (ElementType lhs, ElementType rhs)
{
return lhs == Element && rhs == Element;
}
};
Я обычно делаю создание экземпляров проще, чем ConsecutiveMatcher<wchar_t, L'\\'>()
предоставляя функцию, которая может выводить типы аргументов шаблона на основе типов параметров:
template <typename ElementType>
ConsecutiveMatcher<ElementType, Element /* ?? */>
MakeConsMatcher(ElementType Element)
{
return ConsecutiveMatcher<ElementType, Element>();
}
Однако в этом случае MakeConsMatcher(L'\\')
не будет работать, потому что функция должна возвращать класс, шаблон которого содержит не только тип, но и значение.
Как я могу вернуть шаблон класса из функции, которая имеет не только аргументы шаблона типа, но и аргументы шаблона значения?
Вы хотите, чтобы вычисленное значение во время выполнения превратилось в аргумент шаблона? это невозможно.
Я просто ищу способ пропустить wchar_t и использовать автоматическое удержание типа во время создания экземпляра.
Я могу представить себе такие ситуации:
Тип аргумента известен только во время выполнения (и вы не имеете никакого представления об этом): вы не можете обрабатывать его с помощью шаблонов: вы захотите изменить дизайн своего кода и использовать наследование и виртуальные функции (или, возможно, смешать оба, шаблоны и наследование)
Тип аргумента, известный во время компиляции, значение аргумента, известное во время выполнения: оставил Тип аргумента в списке аргументов шаблона и передать аргумент значение конструктор, затем, для удобства пользователя, сделать функцию фабрики для вывода типа
template<typename T>
struct MyType
{
template <class T>
MyType(const T& defaultValue) :
value(defaultValue)
{}
T value;
};
template<typename T>
MyType<T> MyFactory(const T& defaultValue)
{
return MyType<T>(defaultValue);
}
int main()
{
char c = 'a';
wchar_t w = L'a';
int i = 42;
float f = 3.14f;
auto mt_char = MyFactory(c);
auto mt_wchar = MyFactory(w);
auto mt_int = MyFactory(i);
auto mt_float = MyFactory(f);
}
Во время компиляции вы знаете список типов и хотите, чтобы они вели себя по-разному. (например, имеют разные значения по умолчанию): создайте специализации шаблонов для каждого типа из списка, затем для удобства пользователя создайте typedefs
template<typename T> struct MyType
{
MyType(const T& defaultValue) :
value(defaultValue)
{}
T value;
};
template<>
struct MyType <char>
{
MyType() :
value('c')
{}
char value;
};template<>
struct MyType <wchar_t>
{
MyType() :
value(L'w')
{}
wchar_t value;
};
typedef MyType<char> MyTypeChar;
typedef MyType<wchar_t> MyTypeWchar;
int main()
{
MyTypeChar mt_char_default;
MyTypeWchar mt_wchar_default;
}
В этом случае пользователь все еще может создавать свои собственные специализации. Примером такого подхода является std::basic_string
учебный класс.
Кроме того, вы можете упростить свою специализацию, если сделать членов класса static
или же static const
а для целочисленных типов просто определите в списке членов:
template<>
struct MyType <char>
{
static const char value = 'c';
};