templates and generic programming
Suppose you have written a function to find the maximum of two ints, and now you want the same logic for doubles, for strings, for your own types. In C you might copy-paste it or reach for a void* and lose type safety. C++ templates let you write the code once with the type left as a blank to be filled in, and the compiler stamps out a concrete, fully type-checked version for each type you actually use. This is generic programming: algorithms and data structures written in terms of 'some type T' rather than a fixed type.
A template is a recipe, not code itself. When you write template<class T> T max(T a, T b) {...} nothing is compiled yet; only when you call max(3, 4) does the compiler perform instantiation — it substitutes T = int and generates a real max<int> function, then type-checks that. Call it with doubles and it generates a separate max<double>. You can also write specializations: a hand-tuned version of the template for one specific type that the compiler prefers over the general recipe. Templates work on types and on compile-time constant values, and they are how std::vector, std::unique_ptr, and almost all of the standard library are written — one body that becomes many concrete types.
Why it matters: templates give you the abstraction of generic code with the speed of hand-written, type-specific code, because the substitution happens entirely at compile time — this is a pillar of the zero-overhead principle, sometimes called monomorphization. The honest costs: each distinct instantiation generates separate machine code, which can bloat the binary; templates compile slowly; and template error messages are famously long because the failure often surfaces deep inside the generated code rather than at your call. Concepts (C++20) were added largely to make those errors say what you actually did wrong.
template<class T> T max(T a, T b) { return a < b ? b : a; } // max(3,4) instantiates max<int>; max(1.5,2.5) instantiates max<double>
One template body; the compiler generates a separate, fully type-checked function per type you actually call it with.
A template is not real code until instantiated, so an error in a template branch you never use may go unnoticed until someone calls it with a type that exercises that branch. This is also why heavy template code can silently inflate compile times and binary size.