...

/

The Curiously Recurring Template Pattern

The Curiously Recurring Template Pattern

Learn to implement the CRTP and unlock its potential to simplify and optimize C++ code.

The pattern discussed in this lesson has a rather curious name: the Curiously Recurring Template Pattern, or CRTP for short. It’s called curious because it’s rather odd and unintuitive. The pattern was first described (and its name coined) by James Coplien in a column in the C++ Report in 1995. This pattern is as follows:

  • There is a base class template that defines the (static) interface.

  • Derived classes are themselves the template argument for the base class template.

  • The member functions of the base class call member functions of its type template parameter (which are the derived classes).

Let’s see how the pattern implementation looks in practice. We’ll transform the previous example with game units into a version using the CRTP. The pattern implementation goes as follows:

template<typename T>
struct game_unit
{
void attack()
{
static_cast<T*>(this)->do_attack();
}
};
struct knight : game_unit<knight>
{
void do_attack()
{ std::cout << "draw sword\n"; }
};
struct mage : game_unit<mage>
{
void do_attack()
{ std::cout << "spell magic curse\n"; }
};
A possible CRTP implementation for the game_unit class

The game_unit class is now a template class but contains the same member function, attack. Internally, this performs an upcast of the this pointer to T* and then invokes a member function called do_attack. The knight and mage classes derive from the game_unit class and pass themselves as the argument for the type template parameter T. Both provide a member function called do_attack.

Notice that the member function in the base class template and the called member function in the derived classes have different names. Otherwise, if they had the same name, the derived class member functions would hide the member from the base since these are no longer virtual functions.

The fight function that takes a collection of game units and calls the attack function needs to change too. It needs to be implemented as a function template, as follows:

template<typename T>
void fight(std::vector<game_unit<T>*> const & units)
{
for (auto unit : units)
{
unit->attack();
}
}
Implementation for the fight function

Using this function is a little different than before. It goes as follows:

Press + to interact
knight k;
mage m;
fight<knight>({ &k });
fight<mage>({ &m });

We have moved the runtime polymorphism to compile-time. Therefore, the fight function can’t treat knight and mage objects polymorphically. Instead, we get two different overloads, one that can handle knight objects and one that can handle mage objects. This is static polymorphism.

Although the pattern might not look complicated after all, the question we’re probably asking ourselves at this point is, How is this pattern actually useful?

There are different problems we can solve using CRT, including the following:

  • Limiting the number of times a type can be instantiated

  • Adding common functionality and avoiding code duplication

  • Implementing the composite design pattern

In this lesson, we’ll look at each of these problems and see how to ...