Curiously Recurring Template Pattern (CRTP)

Introduced after showcasing Visitor Pattern, and how there was much code, because there is going to be a lot of methods. Learned in CS247 - Software Engineering Principles.

CRTP is a C++ programming pattern that involves creating a template class with a derived class as its template parameter. This allows the template class to know the type of the derived class and use it as if it were a base class.

Template our superclass with a type parameter - inherit AND substitute the derived class type.

Learned in CS247 - Software Engineering Principles.

Why CRTP exists?

We can’t copy an abstract class, thus why we use CRTP.

For example go to Lecture 21 in CS247 Lectures. But end-result:

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);

Another problem CRTP can solve: polymorphic cloning. Recall abstract books.

No relations between Template Method Pattern and CRTP

The two are unrelated. Template method pattern uses the word template as in English: the draw algorithm for turtles provides a “template” as to what all invocations of draw should look like.

CRTP on the other hand, is referring to C++ templates, i.e classes that can be parameterized on a type.

AbstractBook example:

class AbstractBook{
	public:
		virtual AbstrackBook* clone = 0;
		virtual ~AbstrackBook(){}
};
 
template<typename T> class BookClonable: public AbstrackBook {
	public:
		T* clone() override {
			return T{*static_cast<T*>(this)}
		}
 
		virtual ~BookClonable() = 0;
};
 
template<typnename T> BookClonable<T>::BookClonable<T>(){}
 
class Text: public BookClonable<Text>{...}
class Comic: public BookClonable<Comic>{...}
 
AbstrackBook* b = new Text{...} / new Comic{...};
AbstrackBook* b2 = b->clone():

w

Example:

// A class that defines `operator<` can define the other methods in terms of the < operator. For example: (a > b) is equivalent to (b < a). (a == b) is equivalent to !(a < b) && !(b < a). Write a CRTP class Compareable. Compareable should add the various comparison operators to a class that supports operator<. Give an example of a class that implements operator< and show how Compareable can be used with it. Explain why one might prefer this over an abstract class "AbstractCompareable" that defines the various comparison operators in terms of <, and defines operator< as a virtual method to be overridden in the subclass.
 
#include <iostream>
using namespace std;
 
template <typename T> class Comparable {
    public:
        friend bool operator>(const T& lhs, const T& rhs) {
            return rhs < lhs;
        }
 
        friend bool operator>=(const T& lhs, const T& rhs) {
            return !(lhs < rhs);
        }
 
        friend bool operator<=(const T& lhs, const T& rhs) {
            return !(lhs > rhs);
        }
 
        friend bool operator==(const T& lhs, const T& rhs) {
            return !(lhs < rhs) && !(lhs > rhs);
        }
 
        friend bool operator!=(const T& lhs, const T& rhs) {
            return !(lhs == rhs);
        }
};
 
// example of how to use the Comparable CRTP class with a class that implements operator<
class RandomName : public Comparable<RandomName> {
	int x;
    public:
        RandomName(int x) : x(x) {}
        friend bool operator<(const RandomName& lhs, const RandomName& rhs) {
            return lhs.x < rhs.x;
        }
};
 
int main() {
    RandomName a(1);
    RandomName b(2);
    cout << (a < b) << endl;
    cout << (a > b) << endl;
    cout << (a <= b) << endl;
    cout << (a >= b) << endl;
    cout << (a == b) << endl;
    cout << (a != b) << endl;
    RandomName c(5);
    RandomName d(10);
    if (c < d) std::cout << "a is less than b" << std::endl;
 
    if (c > d) std::cout << "a is greater than b" << std::endl;
 
    if (c == d) std::cout << "a is equal to b" << std::endl;
 
    return 0;
}
 
// Explain why one might prefer this over an abstract class "AbstractCompareable" that defines the various comparison operators in terms of <, and defines operator< as a virtual method to be overridden in the subclass.
 
// The CRTP class is more efficient than the abstract class because the abstract class requires a virtual function call, which is slower than a normal function call. The CRTP class is also more flexible because it allows the subclass to define operator< in terms of other operators, such as operator==. The abstract class does not allow this flexibility because it requires operator< to be defined in terms of operator<.
 
}