C++ Templates & Generic Programming: Function Templates, Class Templates, Specialization & SFINAE (C++23)

C++ Templates & Generic Programming: Function Templates, Class Templates, Specialization & SFINAE (C++23)
Table of Contents
- How Template Instantiation Works
- Function Templates: Type Deduction Rules
- Class Templates: Building Generic Containers
- Non-Type Template Parameters (NTTPs)
- Template Specialization: Full and Partial
- Variadic Templates and Fold Expressions
- if constexpr: Compile-Time Branching (C++17)
- SFINAE and std::enable_if: Constraining Templates
- Variable Templates (C++14)
- Template Instantiation and Code Bloat
- Frequently Asked Questions
- Key Takeaway
How Template Instantiation Works
Templates are not compiled until instantiated. The compiler generates a fresh, type-specific version for each unique set of type arguments. Each version is a fully independent function — no virtual dispatch, no boxing, full inlining.
Function Templates: Type Deduction Rules
Class Templates: Building Generic Containers
Non-Type Template Parameters (NTTPs)
NTTPs let you pass compile-time constants as template arguments — enabling truly zero-overhead fixed-size abstractions:
Template Specialization: Full and Partial
Variadic Templates and Fold Expressions
if constexpr: Compile-Time Branching (C++17)
if constexpr evaluates the condition at compile time — the false branch is completely discarded, never compiled:
SFINAE and std::enable_if: Constraining Templates
SFINAE (Substitution Failure Is Not An Error) — if template substitution fails, the overload is silently removed:
Frequently Asked Questions
Why must templates be in header files?
Because the compiler needs the full template definition to instantiate it. When you include a header, the compiler sees the template definition and can generate the specialized code. If the definition is in a .cpp file, other translation units can't instantiate it. Exception: extern template can suppress re-instantiation across TUs, and C++20 modules eliminate the header requirement entirely.
What is "code bloat" and how do I prevent it?
Each unique instantiation generates separate machine code. std::vector<int> and std::vector<double> generate separate versions of all member functions — potentially doubling binary size. Mitigations: (1) Use type-erased base implementations (like std::vector<void*> backing smaller wrappers), (2) Use extern template to instantiate in one TU, (3) Use std::function for callables, (4) C++20 modules reduce repetition.
What is the difference between typename and class in template parameters?
None — template<typename T> and template<class T> are completely interchangeable. typename is preferred in modern code for clarity (the parameter doesn't need to be a class). The only exception: inside a template body, typename is required to disambiguate dependent type names: typename T::value_type.
Key Takeaway
C++ templates are the bridge between high-level expressiveness and bare-metal performance. Every STL container, algorithm, and utility is built on templates. When you understand instantiation, specialization, and SFINAE, you gain the ability to write zero-overhead generic libraries that are impossible in any other mainstream language. C++20 Concepts (next module) make templates readable — the final piece of the template mastery puzzle.
Read next: Concepts & Constraints: Making Templates Readable →
Part of the C++ Mastery Course — 30 modules from modern C++ basics to expert systems engineering.
