The Curiously Recurring Template Pattern (CRTP) and Static Polymorphism
Compile-time dispatch as a zero-overhead alternative to virtual functions
class Widget : public Base<Widget>. Because Base knows the exact derived type at compile time, it can call the derived class's methods directly through a static_cast, with no virtual table, no indirect call, and full inlining. This turns polymorphism into a compile-time decision.
- explain the runtime cost of virtual dispatch and when it is worth avoiding,
- read and write the CRTP shape and understand why the
static_castis safe here, - use CRTP to build static interfaces, inject shared behaviour as mixins, and generate boilerplate operators,
- weigh compile-time dispatch against runtime dispatch and pick the right tool honestly.
1. Recap: what runtime polymorphism costs
You already know virtual functions from the beginner and intermediate courses. When you mark a method virtual and call it through a base pointer or reference, the compiler cannot know the concrete type, so it dispatches at run time through a virtual table (vtable): each polymorphic object carries a hidden vptr that points at its class's table of function addresses.
That flexibility is not free. Every virtual call is an indirect call through a pointer the compiler cannot usually predict, which means:
- the target is not known at compile time, so the call cannot be inlined and the optimiser cannot see through it;
- each object grows by one pointer (
vptr), which matters for small, numerous objects; - the indirection can cost a branch mispredict or cache miss in hot loops.
struct Shape {
virtual double area() const = 0; // resolved at run time via the vtable
virtual ~Shape() = default;
};
double totalArea(const std::vector<Shape*>& v) {
double s = 0;
for (const Shape* p : v)
s += p->area(); // indirect call, cannot be inlined
return s;
}
For most code this cost is negligible and the flexibility is exactly what you want. But when the concrete type is already known at compile time - a numeric kernel, an expression template, a container adaptor - paying for dynamic dispatch is pure waste. CRTP lets you keep the "call the derived implementation" shape while resolving it at compile time.