Article by Ayman Alheraki on January 11 2026 10:38 AM
xxxxxxxxxx
template <typename Derived>struct Base { void interface() { static_cast<Derived*>(this)->implementation(); }};
struct Derived1 : Base<Derived1> { void implementation() { std::cout << "Implementation of Derived1\n"; }};
struct Derived2 : Base<Derived2> { void implementation() { std::cout << "Implementation of Derived2\n"; }};
int main() { Derived1 d1; Derived2 d2;
d1.interface(); // Output: Implementation of Derived1 d2.interface(); // Output: Implementation of Derived2
return 0;}
template <int N>struct Factorial { static constexpr int value = N * Factorial<N - 1>::value;};
template <>struct Factorial { static constexpr int value = 1;};
int main() { std::cout << Factorial::value << std::endl; // Output: 120 return 0;}
The CRTP is a powerful C++ idiom that leverages templates and inheritance for static polymorphism. It allows a base class to access the derived class's members without the overhead of virtual functions.
Template Base Class: The Base class is a template that takes a type parameter Derived. This parameter represents the derived class that will inherit from Base.
Interface Function: The Base class provides an interface function. This function is intended to be called by users of the derived classes.
Static Downcast: Inside the interface function, static_cast<Derived*>(this) is used to downcast the this pointer (which points to the current object) to a pointer of the Derived type. This is safe because the CRTP ensures that the actual object is indeed of the Derived type.
Implementation Function: The derived classes (Derived1 and Derived2) each provide their own implementation function. This function contains the actual logic specific to the derived class.
Inheritance and Instantiation: The derived classes inherit from Base, passing themselves as the template argument (Base<Derived1> and Base<Derived2>). This creates a circular dependency, but it's resolved at compile time.
Usage in main: In the main function, objects of Derived1 and Derived2 are created. When the interface function is called on these objects, it dynamically dispatches to the correct implementation function based on the actual type of the object.
Static Polymorphism: CRTP achieves polymorphism (the ability of objects of different classes to respond to the same function call in their own way) without the runtime overhead of virtual functions. This can lead to performance improvements in certain scenarios.
Customization: CRTP allows the base class to customize its behavior based on the specific derived class.
Code Reuse: CRTP promotes code reuse by allowing the base class to provide common functionality that can be tailored by derived classes.
CRTP is best suited for scenarios where:
Performance is critical and you want to avoid the overhead of virtual functions.
You need to customize the behavior of a base class based on the specific derived class.
You want to promote code reuse by providing common functionality in a base class that can be extended by derived classes.
While CRTP is a powerful tool, it can also be complex and difficult to understand. It's important to use it judiciously and only when its benefits outweigh its complexity. Additionally, be aware of potential issues like multiple inheritance and circular dependencies when using CRTP.