Templates — generic programming
OOP solves reuse through inheritance and interfaces — but only within a type hierarchy. Templates solve a different problem: parameterized code the compiler specializes for every needed type. The algorithm is written once; the compiler emits a version for int, std::string, any user type. Type checking is compile-time; runtime cost is zero.
C++ templates are a full type system, not text-based macros. The compiler checks correctness, deduces types, runs overload resolution and ADL, picks the most specific specialization, and (since C++20) verifies concept constraints. A candidate who confuses substitution failure with a hard error, or who treats templates as "smart macros", lands at junior+ in the best case.
Topic map
- Template basics — function and class templates, the header-only rule.
- Instantiation — implicit/explicit,
extern template, template bloat. - Specialization — full and partial; why no partial spec for functions.
- Additional features — NTTP, template-template parameters, default arguments.
- Variadic templates —
typename...,sizeof..., recursive unpacking. - Pack expansion — the
...operator and fold expressions. - Type deduction — argument deduction,
decltype,auto, CTAD. - SFINAE — substitution failure,
enable_if,void_t, the immediate context. - Concepts (C++20) — named constraints,
requires-expressions. - Static polymorphism / CRTP — dispatch without a vtable.
- constexpr metaprogramming —
constexpr,consteval,if constexpr,constinit. - Dependent names —
typename,template, two-phase lookup.
Common traps
| Mistake | Consequence |
|---|---|
Template function body in .cpp | undefined reference at link time in every TU that uses it |
max(3, 3.14) without explicit T | Conflicting deduction — compiler cannot choose between int and double |
template<> partial specialization for a function | Compile error — overloads only |
| Full specialization after the first use | UB |
| Templated base class + unqualified name | greet() does not find the base's method; needs this->greet() |
Dependent type without typename | Compiler reads T::value_type as a value — syntax error |
| SFINAE error in the body, not the signature | Hard error — not filtered out, compilation fails |
Template class used in 50 TUs without extern template | Compiled many times, slow link step |
Unary fold over + with an empty pack | Error — use binary fold with identity 0 |
auto where you need an exact reference | Copy instead of reference; performance loss — use decltype(auto) |
Interview relevance
Templates are one of the deepest recurring topics at middle and senior C++ interviews. Interviewers check mechanism, not syntax.
What is actually being checked:
- Template argument deduction — why
max(3, 3.14)does not compile, how to fix it. - Instantiation and the header-only rule; ODR and
extern templatefor compile-time control. - Full vs partial specialization; why partial spec is forbidden for functions.
- SFINAE — the immediate context, the difference from a hard error; why concepts are "better".
- Variadic + fold — how a pack actually expands, the four fold forms.
- CRTP — purpose, contrast with virtual functions, common uses.
typenameand two-phase lookup — whythis->method()inside a templated class.
Popular questions:
- Write
is_same<T, U>from scratch (primary template + full specialization). - Build a function that accepts numeric types only — via SFINAE and via concepts.
- How many instantiations does
std::vector<std::vector<int>>produce, and why? - What is SFINAE, and where does "failure is not an error" stop applying?
- Implement
tupleortype_listwith variadic templates. - How is
if constexprdifferent from a plainifand why is it needed inside a template? - Why do you need to write
typename T::value_type?
Common candidate mistake: treating templates as "smart macros". They are not text substitution — they are a type system with overload resolution, ADL, and compile-time checks. Without understanding the difference between substitution failure and hard error, you do not pass middle.