Примечание: следующий вопрос о Шаблон Метод Дизайн Шаблон а также Шаблоны функций C ++. Чтобы различать оба, я буду использовать курсив ссылаясь на шаблон дизайна и смелый при обращении к шаблонам C ++.
Идея шаблонный шаблон сделать части алгоритма взаимозаменяемыми. Обычно это достигается с помощью наследования, где подкласс обеспечивает конкретные реализации, которые подключены к алгоритму базового класса. Однако, если методы ловушки должны быть шаблоны, это не будет работать как шаблоны не может быть виртуальным. Вот простой пример, который не компилируется:
class Base
{
public:
// This is the template method
template <typename T>
void doSomething(T input)
{
//...
auto converted = ConvertInput(input);
//...
std::cout << converted;
}
protected:
//compile error "member function templates cannot be virtual"template <typename T>
virtual T ConvertInput(T input) = 0;
};
class Derived : public Base
{
protected:
template <typename T>
T ConvertInput(T input)
{
return 2 * input;
}
};
int main()
{
Derived d;
d.doSomething(3);
}
Есть ли способ реализовать методы шаблона это использование шаблон функции крюки?
Я не заинтересован в использовании Base
класс как тип где угодно. Я всегда буду использовать конкретный конкретный тип для достижения максимальной оптимизации во время компиляции. Итак, еще одна формулировка этого вопроса: как я могу создать несколько классов Derived-1 .. Derived-n
который имеет шаблоны функций что общего кода скелет между реализациями?
Походит на хороший случай использования для CRTP. определять Base
как шаблон класса с типом, полученным из него в качестве параметра шаблона. внутри Base
методы, которые вы можете привести к производному типу:
template<typename Derived>
struct Base
{
// This is the template method
template <typename T>
void doSomething(T input)
{
//...
auto converted = static_cast<Derived*>(this)->ConvertInput(input);
//...
std::cout << converted << std::endl;
}
};
А затем определите производные типы, например:
struct Square : Base<Square>
{
template<typename T>
auto ConvertInput(T t)
{
return t*t;
}
};
struct Sum : Base<Sum>
{
template<typename T>
auto ConvertInput(T t)
{
return t+t;
}
};
использование довольно тривиально:
Square sq;
Sum sum;
sq.doSomething(3);
sum.doSomething(3);
CRTP решает вашу проблему, делая Base шаблоном.
Если T
происходит из конечного набора, или преобразование не произвольно, стирание типа может работать.
Если конечный набор, тип стереть все производные виртуальные методы. Если это общее свойство, введите стереть это свойство и виртуализировать метод, который действует на него. Или смесь.
В противном случае у Base могут быть методы шаблона, которые принимают операцию как объект функции (с шаблоном operator()
) вместо использования виртуального, чтобы найти его. Производный передает шаблонные операции в качестве аргументов базовому методу (методам). Это в основном CRTP без CRTP.