Template Metaprogramming
Turning the compiler into a program that computes types and values before your code ever runs
- explain the two-phase model: what the compiler computes vs. what the CPU computes;
- move computation to compile time with
constexprfunctions andconsteval(C++20); - inspect and transform types with the
<type_traits>library; - branch on types inside one function with
if constexprinstead of tangled overloads; - enforce contracts at compile time with
static_assert, and know the real trade-offs of TMP.
1. Two worlds: compile time and run time
Every C++ program lives in two worlds. In the compile-time world the compiler manipulates types and constant expressions, instantiates templates, and evaluates constexpr code. In the run-time world the CPU executes the machine code that survived compilation. Metaprogramming is the craft of doing as much useful work as possible in the first world so the second world has less to do.
You already know templates from the intermediate course: template<typename T> lets one definition serve many types. The key insight for TMP is that template instantiation is itself a computation. When you write std::vector<int>, the compiler runs the vector template with the argument int and produces a brand-new type. Feed a template different arguments and it computes different types — that is a pure function from types (and values) to types (and values), executed by the compiler.
Why bother? Three concrete pay-offs:
- Speed: a value computed at compile time is a literal in the binary; the CPU never recomputes it.
- Safety: a mistake caught during compilation can never reach a user.
static_assertturns a logic error into a build error. - Generality without cost: one generic algorithm can specialize itself per type with zero run-time branching.