Note: The following question is about the Template Method Design Pattern and C++ function templates. To distinguish both, I will use italics when referring to the design pattern and bold when referring to C++ templates.
The idea of the template method pattern is to make parts of an algorithm exchangeable. This is usually achieved via inheritance, where the subclass provides concrete implementations that are plugged into an algorithm of the base class. However, if the hook methods need to be templates, this will not work as templates cannot be virtual. Here is a simple example that does not compile:
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);
}
Is there a way to implement template methods that use function template hooks?
I am not interested in using the Base
class as a type anywhere. I will always use the concrete specific type to achieve a maximum of compile-time optimization. So another formulation of this question is: How can I create several classes Derived-1 .. Derived-n
that have function templates that share a common code skeleton across the implementations?
Sounds like a fine use-case for CRTP. Define Base
as a class template with the type derived from it as the template parameter. Inside Base
's methods you can cast down to the derived type:
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;
}
};
And then define the derived types, for example:
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;
}
};
the usage is pretty trivial:
Square sq;
Sum sum;
sq.doSomething(3);
sum.doSomething(3);