Curiously Recurring Template Pattern (CRTP)
Learned in CS247.
When to use this pattern?
There are 2 use cases:
- Reduce boilerplate code while maintaining compile-time polymorphism
- Polymorphic cloning
So it seems that with CRTP, you always have 3 layers in the hierarchy, due to the nature of the templates, which means that they are actually different superclasses, so you have to have these superclasses inherit from a higher superclass that doesn’t use templates.
Motivation
Introduced after showcasing Visitor Pattern, and how there was much code, because there is going to be a lot of methods: if we have subclasses of and subclasses of : different methods to write.
Annoying part: Boilerplate - write the following in each DerivedEnemy:
class DerivedEnemy: public Enemey {
public:
void beStruckBy(Weapon& w) {
w.strike(*this);
}
};- must be one for every single
DerivedEnemy - Cannot put it in
Enemy:
class Enemy {
public:
void beStruckBy(Weapon& w) {
w.strike(*this); // this is just an Enemy
}
};However, notice that this doesn’t work - the type of this is wrong. It’s not telling us what the dynamic type is.
Solution to fixing the boilerplate code is to use Curiously Recurring Template Pattern (CRTP).
Example 1
Template our superclass with a type parameter - inherit, AND substitute the derived class type.
template<typename T> class Base {
...
};
class Derived: public Base<Derived> { // At this point, we know Derived is a class.
... // use T in Base as if had provided a forward declaration
}How do we use this to fix the boilerplate code?
template<typename T> class Enemy {
public:
void beStruckBy() {
w.strike(*static_cast<T*>(this));
}
};
class Monster: public Enemy<Monster> {...};
class Turtle: public Enemy<Turtle> {...};This sort of works
Weapon* w = ...;
Turtle t{...};
t.beStruckBy(*w); // Calls Enemy<Turtle>::beStruckByCast this from type Enemy<Turtle>* to Turtle* allows us to override into Rock::Strike(Turtle&) and Stick::Strike(Turtle&).
Issue: Now, we have different superclasses for each Enemy

Because Enemy<Turtle> and Enemy<Monster> are different classes: can no longer use Enemys polymorphically - no vector<Enemy*> allowed!
Solution: Add another layer of inheritance.

class Enemy {
public:
virtual void beStruckBy(Weapon& w) = 0;
virtual ~Enemy() {}
};
template<typename T> class EnemyBeStruck: public Enemy {
public:
void beStruckBy(Weapon& w) override {
w.strike(*static_cast<T*>(this));
}
virtual ~EnemyBeStruck() = 0;
}
template<typename T> EnemyBeStruck<T>::~EnemyBeStruck<T>() {}
class Turtle: public EnemyBeStruck<Turtle> {...}
class Monster: public EnemyBeStruck<Monster> {...}Now, we have a public interface by which all our concrete enemies follow: can all beStruckBy weapons. We use the virtual method in Enemy to resolve beStruckBy to either EnemyBeStruck<Turtle> or EnemyByStruck<Monster> . Then just static_cast to T* - and we’re good.
Weapon* w = ...;
Enemy* e = new Turtle{...} / new Monster{...};
e->beSstruckBy(*w);Example #2
Another problem CRTP can solve: polymorphic cloning.
Recall abstract books:

Say I have:
AbstractBook* b = ...;I want a deep copy of whatever b points to. I cannot just do this:
AbstractBook* b2 = new AbstractBook{*b};This attempts to create an AbstractBook by invoking its constructor. Wrong for 2 reasons:
AbstractBookis abstract, cannot instantiate those objects- Ignoring what we’re actually pointing at, we actually want to invoke a constructor that depends on the dynamic type of
b
We can provide a virtual clone method for the purpose of solving this:
class AbstractBook {
public:
virtual AbstractBook* clone() = 0;
virtual ~AbstractBook() {};
};
class Text: public AbstractBook {
public:
Text* clone() override {
return new Text{title, author, length, topic};
}
};
// Comic and NormalBook are similar
AbstractBook* b = ...;
AbstractBook* b2 = b->clone();Instead use the copy ctor in each of our clone methods to simplify the implementation.
class Text: public AbstractBook {
public:
Text* clone() override {
return new Text{*this};
}
};Exact same code in MermaidBook and Comic - just the type of this and the type of ctor which is changing. Once again, we can use CRTP.
class AbstractBook {
public:
virtual AbstractBook* clone() = 0;
virtual ~AbstractBook() {};
};
template<typename T> class BookClonable: public AbstractBook {
public:
T* clone() override {
return new T{*static_cast<T*>(this)};
}
virtual ~BookClonable() = 0;
};
template<typename T>
BookClonable<T>::~BookClonable<T>() {};
class Text: public BookClonable<Text> {...};
class Comic: public BookClonable<Comic> {...};
AbstractBook* b = new Text{...} / new Comic {...};
AbstractBook* b2= b->clone();b->clone is virtual, so if b points at a Comic, we call BookClonable<Comic>::clone - static_cast this into a Comic* and invoke the Comic copy constructor with the Comic&.
Provided for all subclasses - reduces boilerplate code.