Author image

Curiously Recurring Template Pattern


Difficulty:
1/5


Curiously Recurring Template Pattern, or CRTP for short, is essentially a C++ only idiom. It is also known as Static Polymorphism or Simulated polymorphism.

Requirements for dynamic polymorphism:

  1. Is-a relationship between base and derived class.
  2. Base class defines a 'generic' algorithm that is used by derived class.
  3. The 'generic' algorithm is customized by the derived class.

Requirements for static polymorphism:

  1. 'Is-a' relationship between base and derived class.
  2. Base class defines a 'generic' algorithm that is used by derived class.
  3. The 'generic' algorithm is customized by the derived class.
  4. This method is pure virtual. The derived method implements it.

However, to avoid run time costs when the specialized method is invariant of the one in the base method then this resolution can be achieved at compile time using templated code. Templates do away with run-time virtual-table lookups. Then the pattern in use is the CRTP; it is simulating dynamic polymorphism without any runtime performance penalty.

Benefits

  • All benefits of dynamic (actual) polymorphism without additional performance cost
  • The client still sees and uses the polymorphic function as an actual polymorphic function, having no idea about its templatedness

Disadvantages

  • space heavy - larger image size due to templatized code
  • Virtual methods are more powerful in the sense that, unlike the CRTP, they are able to discover the implementation of an interface at each runtime call. This is dynamic polymorphism. Each object* can change the implementation by newing a new OtherDerivedClass(); and then running a function on it. With CRTP we get static polymorphism; ie B is A, but it can't change to C (which also inherits from A) during runtime. Thus the cost is flexibility.

Truth be told, this is a significant weakness of CRTP, which is why you should use it only when performance is critical and you are absolutely certain you don't need to change behavior at runtime - which kind of breaks the need of virtual functions in the first place, but I'm sure you can find a use for it : ).

Design

  • base class is a (concrete) template class
  • derived class in a non-template class which derives from the base class with template type argument being its own type
  • only derived class objects are to be created
  • base class defines an interface like method which calls the appropriate implementation method of a derived class based on the type of the calling object it receives as argument. The interface and the implementation method need not have the same signature
  • To accomplish this at compile time the interface method calls the implementation method like so: static_cast<T*>( this )->implementation( args... ).

Blueprint:

template<class Derived>
struct Base
{
    void interface()
    {
        // ...
        static_cast<Derived*>( this )->implementation();
// or: // static_cast<Derived const&>( *this ).implementation(); // if you prefer by reference // ... } }; struct Derived1 : public Base<Derived1> { void implementation() { // ... } }; struct Derived2 : public Base<Derived2> { void implementation() { // ... } };

As usual I used Windows 8.1 x86_64, Visual Studio 2017 to build the project.

Github

Github repository link.


0 likes