The CRTP Idiom
Curiously recurring template pattern.
The CRTP Idiom is a free C++ Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C++ Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is CRTP?
The Curiously Recurring Template Pattern (CRTP) is a C++ idiom where a class Derived inherits from a template base instantiated with Derived itself.
- Shape:
class Derived : public Base<Derived> - The base learns its derived type at compile time
template <typename T>
class Base {};
class Derived : public Base<Derived> {};The Core Mechanism
Inside the base, you can static_cast the this pointer to the derived type. Because the derived type is a template parameter, this is a fully compile-time cast with no runtime cost.
#include <iostream>
template <typename T>
class Base {
public:
void interface() {
static_cast<T*>(this)->implementation();
}
};
class Derived : public Base<Derived> {
public:
void implementation() { std::cout << "Derived impl\n"; }
};
int main() {
Derived d;
d.interface();
return 0;
}Why "Curiously Recurring"?
The name comes from the apparent paradox: the base class refers to the derived class, which is not yet fully defined when the base template is written.
- It works because templates are only instantiated when used
- By instantiation time,
Derivedis a complete type
A First Real Use
CRTP lets a base provide reusable functionality that calls back into the derived class. Here the base supplies a print() that delegates to the derived name().
#include <iostream>
#include <string>
template <typename T>
struct Named {
void print() {
std::cout << static_cast<T*>(this)->name() << "\n";
}
};
struct Cat : Named<Cat> {
std::string name() { return "Cat"; }
};
int main() {
Cat c;
c.print();
return 0;
}No Virtual Tables
Unlike runtime polymorphism, CRTP needs no virtual keyword and no vtable pointer in each object. Dispatch is resolved entirely at compile time.
- Smaller objects (no hidden vptr)
- Calls can be inlined
Counting Instances
A classic CRTP application is an object counter. Each derived class gets its own static counter automatically.
#include <iostream>
template <typename T>
struct Counter {
static inline int count = 0;
Counter() { ++count; }
~Counter() { --count; }
};
struct Widget : Counter<Widget> {};
int main() {
Widget a, b;
std::cout << Widget::count << "\n";
return 0;
}Each Derived Gets Its Own State
Because Counter<Widget> and Counter<Gadget> are distinct template instantiations, each has an independent static count. This separation is impossible with a single non-template base.
#include <iostream>
template <typename T>
struct Counter {
static inline int count = 0;
Counter() { ++count; }
};
struct A : Counter<A> {};
struct B : Counter<B> {};
int main() {
A a1, a2;
B b1;
std::cout << A::count << " " << B::count << "\n";
return 0;
}The static_cast Is Safe Here
The downcast inside the base is safe only if every object of type Base<T> truly is a T. CRTP guarantees this by construction, since T is the class that inherits.
- Never instantiate
Base<Wrong>for an unrelated class
Comparison Operators via CRTP
You can synthesize a full set of comparison operators from a single operator< by deriving from a comparison helper.
#include <iostream>
template <typename T>
struct Comparable {
friend bool operator>(const T& a, const T& b) { return b < a; }
friend bool operator==(const T& a, const T& b) { return !(a < b) && !(b < a); }
};
struct Num : Comparable<Num> {
int v;
Num(int x) : v(x) {}
friend bool operator<(const Num& a, const Num& b) { return a.v < b.v; }
};
int main() {
std::cout << (Num(3) > Num(2)) << "\n";
return 0;
}Protected Constructor Guard
To prevent accidental misuse of the base, give it a protected constructor so only derived classes can create it.
#include <iostream>
template <typename T>
class Base {
protected:
Base() = default;
public:
void run() { static_cast<T*>(this)->step(); }
};
class Job : public Base<Job> {
public:
void step() { std::cout << "step\n"; }
};
int main() {
Job j;
j.run();
return 0;
}CRTP in Standard Libraries
CRTP appears throughout real C++ libraries.
std::enable_shared_from_this<T>uses it- Many expression-template math libraries (Eigen) rely on it
- Ranges and iterator helpers use similar patterns
Recognizing the shape X : Base<X> helps you read advanced code.
Quick Check
Test your understanding of the CRTP shape.
Recap
You learned the CRTP idiom.
Derived : Base<Derived>gives the base its concrete type- A
static_cast<T*>(this)enables compile-time dispatch - No vtable, smaller objects, inlinable calls
- Used for counters, comparison mixins, and library helpers
Frequently asked questions
Is the “The CRTP Idiom” lesson free?
Yes — the full text of “The CRTP Idiom” is free to read here on the web, and the C++ Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C++ Academy course, upgrade to CoddyKit PRO.
What will I learn in “The CRTP Idiom”?
Curiously recurring template pattern. You practise C++ Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C++ Academy?
No prior experience is required. C++ Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “The CRTP Idiom” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C++ Academy lesson?
Yes. Every C++ Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- The CRTP Idiom
- Static Polymorphism
- Mixins with CRTP
- When to Use CRTP