Worldscope

Curiously Recurring Template Pattern (CRTP) in C++

Palavras-chave:

Publicado em: 06/08/2025

Curiously Recurring Template Pattern (CRTP) in C++

The Curiously Recurring Template Pattern (CRTP) is a C++ design pattern in which a class X derives from a class template instantiation Base<X>. This seemingly circular dependency allows the base class to access the derived class's methods and members without virtual functions or runtime polymorphism, leading to potential performance benefits. This article will explore the CRTP, its implementation, advantages, and alternatives.

Fundamental Concepts / Prerequisites

To understand CRTP, you should have a solid grasp of the following C++ concepts:

  • Templates: Class templates and function templates are essential for defining generic code that can work with different types.
  • Inheritance: Understanding single and multiple inheritance is crucial for creating derived classes from base classes.
  • Static Polymorphism: CRTP enables static polymorphism, where the behavior of a function is determined at compile time based on the actual type of the derived class.
  • Class Derivation: The derived class and its methods and members.

Core Implementation/Solution

Here's a simple example of the CRTP:


template <typename Derived>
class Base {
public:
  void interface() {
    // Static cast to the derived class
    static_cast<Derived*>(this)->implementation();
  }
};

class Concrete : public Base<Concrete> {
public:
  void implementation() {
    // Specific implementation for Concrete class
    std::cout << "Concrete::implementation() called\n";
  }
};

int main() {
  Concrete obj;
  obj.interface(); // Calls Concrete::implementation()
  return 0;
}

Code Explanation

The Base class is a template that takes the derived class (Derived) as a template parameter. The interface() method in the Base class uses a static_cast to convert the this pointer (which is a pointer to the Base class) to a pointer to the Derived class. This allows the interface() method to call the implementation() method of the Derived class. Because the cast is performed at compile time, the overhead associated with virtual function calls is avoided.

The Concrete class inherits from Base<Concrete>, completing the "curious" recursion. The Concrete class provides the implementation() method, which is called by the interface() method of the Base class.

Note that this relies on the derived class actually having an `implementation()` method.

Complexity Analysis

The CRTP introduces **no runtime overhead**. The static_cast and function calls are resolved at compile time. Therefore, the time complexity of accessing a derived class's method through the base class interface is **O(1)**. The space complexity is also not directly affected by CRTP, since it is essentially the same as normal inheritance. The memory footprint is determined by the members of the base and derived classes, not by the CRTP pattern itself.

Alternative Approaches

Traditional virtual functions provide a more common way to achieve polymorphism at runtime. The trade-off is a slight performance overhead due to the virtual function table lookup. Virtual functions are also more flexible since the actual type of the object can be determined at runtime, allowing for dynamic polymorphism. However, in situations where the type of the object is known at compile time and performance is critical, CRTP offers a compelling alternative.

Another alternative is using function objects (functors) and the Strategy pattern. This can reduce code duplication. However, it might increase the number of classes and introduce an extra level of indirection.

Conclusion

The Curiously Recurring Template Pattern is a powerful C++ technique for achieving static polymorphism and avoiding runtime overhead. It allows base classes to utilize derived class functionality without virtual function calls, resulting in potential performance gains. While it may not be suitable for all situations due to its reliance on compile-time type information, CRTP offers a valuable tool for optimizing performance-critical code in scenarios where the derived class's type is known at compile time.