What the Curiously Recurring Template Pattern can bring to your code

After having defined the basics on the CRTP in episode #1 of the series, let’s now consider how the CRTP can be helpful in day-to-day code.

The episodes in this series are:

The CRTP, episode One: Definition

The CRTP, episode Two: What the CRTP can bring to your code

The CRTP, episode Three: An implementation helper for the CRTP

I don’t know about you, but the first few times I figured how the CRTP worked I ended up forgetting soon after, and in the end could never remember what the CRTP exactly was. This happened because a lot of definitions of CRTP stop there, and don’t show you what value the CRTP can bring to your code.

But there are several ways the CRTP can be useful. Here I am presenting the one that I see most in code, Adding Functionality, and another one that is interesting but that I don’t encounter as often: creating Static Interfaces.

In order to make the code examples shorter, I have omitted the private-constructor-and-template-friend trick seen in episode One. But in practice you would find it useful to prevent the wrong class from being passed to the CRTP template.

Adding functionality

Some classes provide generic functionality, that can be re-used by many other classes.

To illustrate this, let’s take the example of a class representing a sensitivity. A sensitivity is a measure that quantifies how much a given output would be impacted if a given input to compute it were to vary by a certain amount. This notion is related to derivatives. Anyway if you’re not (or no longer) familiar with maths, fear not: the following doesn’t depend on mathematical aspects, the only thing that matters for the example is that a sensitivity has a value.

class Sensitivity { public: double getValue() const; void setValue(double value); // rest of the sensitivity's rich interface... }; 1 2 3 4 5 6 7 class Sensitivity { public : double getValue ( ) const ; void setValue ( double value ) ; // rest of the sensitivity's rich interface... } ;

Now we want to add helper operations for this sensitivity, like scaling it (multiplying it by a constant value), and say squaring it or setting it to the opposite value (unary minus). We can add the corresponding methods in the interface. I realize that in this case it would be good practice to implement these functionalities as non-member non-friend functions, but bear with me just a moment and let’s implement them as methods, in order to illustrate the point that is coming afterwards. We will come back to this.

class Sensitivity { public: double getValue() const; void setValue(double value); void scale(double multiplicator) { setValue(getValue() * multiplicator); } void square() { setValue(getValue() * getValue()); } void setToOpposite() { scale(-1); }; // rest of the sensitivity's rich interface... }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Sensitivity { public : double getValue ( ) const ; void setValue ( double value ) ; void scale ( double multiplicator ) { setValue ( getValue ( ) * multiplicator ) ; } void square ( ) { setValue ( getValue ( ) * getValue ( ) ) ; } void setToOpposite ( ) { scale ( - 1 ) ; } ; // rest of the sensitivity's rich interface... } ;

So far so good. But imagine now that we have another class, that also has a value, and that also needs the 3 numerical capabilities above. Should we copy and paste the 3 implementations over to the new class?

By now I can almost hear some of you scream to use template non-member functions, that would accept any class and be done with it. Please bear with me just another moment, we will get there I promise.

This is where the CRTP comes into play. Here we can factor out the 3 numerical functions into a separate class:

template <typename T> struct NumericalFunctions { void scale(double multiplicator); void square(); void setToOpposite(); }; 1 2 3 4 5 6 7 template < typename T > struct NumericalFunctions { void scale ( double multiplicator ) ; void square ( ) ; void setToOpposite ( ) ; } ;

and use the CRTP to allow Sensitivity to use it:

class Sensitivity : public NumericalFunctions<Sensitivity> { public: double getValue() const; void setValue(double value); // rest of the sensitivity's rich interface... }; 1 2 3 4 5 6 7 class Sensitivity : public NumericalFunctions < Sensitivity > { public : double getValue ( ) const ; void setValue ( double value ) ; // rest of the sensitivity's rich interface... } ;

For this to work, the implementation of the 3 numerical methods need to access the getValue and setValue methods from the Sensitivity class:

template <typename T> struct NumericalFunctions { void scale(double multiplicator) { T& underlying = static_cast<T&>(*this); underlying.setValue(underlying.getValue() * multiplicator); } void square() { T& underlying = static_cast<T&>(*this); underlying.setValue(underlying.getValue() * underlying.getValue()); } void setToOpposite() { scale(-1); }; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 template < typename T > struct NumericalFunctions { void scale ( double multiplicator ) { T & underlying = static_cast < T & > ( * this ) ; underlying . setValue ( underlying . getValue ( ) * multiplicator ) ; } void square ( ) { T & underlying = static_cast < T & > ( * this ) ; underlying . setValue ( underlying . getValue ( ) * underlying . getValue ( ) ) ; } void setToOpposite ( ) { scale ( - 1 ) ; } ; } ;

This way we effectively added functionality to the initial Sensitivity class by using the CRTP. And this class can be inherited from by other classes, by using the same technique.

Why not non-member template functions?

Ah, there we are.

Why not use template non-member functions that could operate on any class, including Sensitivity and other candidates for numerical operations? They could look like the following:

template <typename T> void scale(T& object, double multiplicator) { object.setValue(object.getValue() * multiplicator); } template <typename T> void square(T& object) { object.setValue(object.getValue() * object.getValue()); } template <typename T> void setToOpposite(T& object) { object.scale(object, -1); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 template < typename T > void scale ( T & object , double multiplicator ) { object . setValue ( object . getValue ( ) * multiplicator ) ; } template < typename T > void square ( T & object ) { object . setValue ( object . getValue ( ) * object . getValue ( ) ) ; } template < typename T > void setToOpposite ( T & object ) { object . scale ( object , - 1 ) ; }

What’s all the fuss with the CRTP?

There is at least one argument for using the CRTP over non-member template functions: the CRTP shows in the interface.

With the CRTP, you can see that Sensitivity offers the interface of NumericalFunctions :

class Sensitivity : public NumericalFunctions<Sensitivity> { public: double getValue() const; void setValue(double value); // rest of the sensitivity's rich interface... }; 1 2 3 4 5 6 7 class Sensitivity : public NumericalFunctions < Sensitivity > { public : double getValue ( ) const ; void setValue ( double value ) ; // rest of the sensitivity's rich interface... } ;

And with the template non-member functions you don’t. They would be hidden behind a #include somewhere.

And even if you knew the existence of these 3 non-member functions, you wouldn’t have the guarantee that they would be compatible with a particular class (maybe they call get() or getData() instead of getValue() ?). Whereas with the CRTP the code binding Sensitivity has already been compiled, so you know they have a compatible interface.

Who’s Your Interface Now?

A interesting point to note is that, although the CRTP uses inheritance, its usage of it does not have the same meaning as other cases of inheritance.

In general, a class deriving from another class expresses that the derived class somehow conceptually “is a” base class. The purpose is to use the base class in generic code, and to redirect calls to the base class over to code in the derived class.

With the CRTP the situation is radically different. The derived class does not express the fact it “is a” base class. Rather, it expands its interface by inherting from the base class, in order to add more functionality. In this case it makes sense to use the derived class directly, and to never use the base class (which is true for this usage of the CRTP, but not the one described below on static interfaces).

Therefore the base class is not the interface, and the derived class is not the implementation. Rather, it is the other way around: the base class uses the derived class methods (such as getValue and setValue ). In this regard, the derived class offers an interface to the base class. This illustrates again the fact that inheritance in the context of the CRTP can express quite a different thing from classical inheritance.

Static interfaces

The second usage of the CRTP is, as described in this answer on Stack Overflow, to create static interfaces. In this case, the base class does represent the interface and the derived one does represent the implementation, as usual with polymorphism. But the difference with traditional polymorphism is that there is no virtual involved and all calls are resolved during compilation.

Here is how it works.

Let’s take an CRTP base class modeling an amount, with one method, getValue :

template <typename T> class Amount { public: double getValue() const { return static_cast<T const&>(*this).getValue(); } }; 1 2 3 4 5 6 7 8 9 template < typename T > class Amount { public : double getValue ( ) const { return static_cast < T const & > ( * this ) . getValue ( ) ; } } ;

Say we have two implementations for this interface: one that always returns a constant, and one whose value can be set. These two implementations inherit from the CRTP Amount base class:

class Constant42 : public Amount<Constant42> { public: double getValue() const {return 42;} }; class Variable : public Amount<Variable> { public: explicit Variable(int value) : value_(value) {} double getValue() const {return value_;} private: int value_; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Constant42 : public Amount < Constant42 > { public : double getValue ( ) const { return 42 ; } } ; class Variable : public Amount < Variable > { public : explicit Variable ( int value ) : value_ ( value ) { } double getValue ( ) const { return value_ ; } private : int value_ ; } ;

Finally, let’s build a client for the interface, that takes an amount and that prints it to the console:

template<typename T> void print(Amount<T> const& amount) { std::cout << amount.getValue() << '

'; } 1 2 3 4 5 template < typename T > void print ( Amount < T > const & amount ) { std :: cout << amount . getValue ( ) << '

' ; }

The function can be called with either one of the two implementations:

Constant42 c42; print(c42); Variable v(43); print(v); 1 2 3 4 Constant42 c42 ; print ( c42 ) ; Variable v ( 43 ) ; print ( v ) ;

and does the right thing:

42 43 1 2 42 43

The most important thing to note is that, although the Amount class is used polymorphically, there isn’t any virtual in the code. This means that the polymorphic call has been resolved at compile-time, thus avoiding the run-time cost of virtual functions. For more about this impact on performance you can see the study Eli Bendersky made on his (great) website.

From a design point of view, we were able to avoid the virtual calls here because the information of which class to use was available at compile-time. And like we saw in the Extract Interface refactoring at compile-time, when you know the info, why wait until the last moment to use it?

EDIT: As u/quicknir pointed out on Reddit, this technique is not the best one for static interfaces, and nowhere as good as what concepts are expected to bring. Indeed, the CRTP forces to inherit from the interface, while concepts also specify requirements on types, but without coupling them with a specific interface. This allows independent libraries to work together.

Next up: how to make the implementation of the CRTP easy in practice.

Related articles:

Share this post! Don't want to miss out ?