Реализация шаблонного метода

Примечание: следующий вопрос о Шаблон Метод Дизайн Шаблон а также Шаблоны функций 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 который имеет шаблоны функций что общего кода скелет между реализациями?

2

Решение

Походит на хороший случай использования для 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);

живое демо

3

Другие решения

CRTP решает вашу проблему, делая Base шаблоном.

Если T происходит из конечного набора, или преобразование не произвольно, стирание типа может работать.

Если конечный набор, тип стереть все производные виртуальные методы. Если это общее свойство, введите стереть это свойство и виртуализировать метод, который действует на него. Или смесь.

В противном случае у Base могут быть методы шаблона, которые принимают операцию как объект функции (с шаблоном operator()) вместо использования виртуального, чтобы найти его. Производный передает шаблонные операции в качестве аргументов базовому методу (методам). Это в основном CRTP без CRTP.

2

По вопросам рекламы [email protected]