Templates
Course 1 built the OOP foundation. Course 2 starts with the everyday tool that foundation — and the rest of the standard library — is actually built on top of.
The Problem Templates Solve
Writing the same logic separately for every type — a max_int and a separate max_double — is genuinely repetitive. C has no generic mechanism beyond void * plus manual casting (losing type safety entirely) or macros (c2-4's own text-substitution trap, applied to "generic" code with none of the type checking a real function would provide).
Function Templates
Compile-Time Monomorphization
The real mechanism: the compiler generates a separate, fully concrete function for each distinct type actually used. Calling max_value with int and again with double produces two genuinely distinct compiled functions, each fully type-checked and optimized exactly as if hand-written for that specific type — not a single generic, runtime-dispatched function. Zero runtime overhead, at the cost of larger compiled binary size. This is a direct parallel to rust2-3's own generics chapter — Rust uses the identical monomorphization strategy, another rare point of real convergence between the two languages, alongside cpp1-5's own RAII/Drop parallel.
Class Templates
This is exactly the shape cpp2-2's own STL containers use — std::vector<int> genuinely is a template instantiation, not a special built-in construct.
Template Type Deduction
In most cases the compiler infers T from the arguments automatically — max_value(3, 7) works with no need to write max_value<int>(3, 7) explicitly, though the explicit form is always allowed.
A Compile Error You'll See — No Matching Function
If T doesn't support an operation the template body actually uses (e.g. calling max_value on a type with no > operator defined), the error surfaces at the instantiation site, often with a genuinely confusing, deeply nested message — a well-known rough edge of pre-C++20 templates. C++20 concepts improve this substantially; full depth is deferred to cpp3-2's own "Templates, Deeper" chapter.
| Concept | C | C++ Templates | Rust Generics |
|---|---|---|---|
| Generic code | void* + manual casting, or macros — no type safety | templates — fully type-checked | generics — fully type-checked |
| Compilation strategy | n/a | monomorphization — one concrete copy per type used | monomorphization — the same strategy |
| Runtime overhead | n/a | none | none |
cpp1-3/c2-5's own header/definition-separation convention: the compiler needs to see a template's full definition at every point it's instantiated, so template code is typically written entirely in the header itself, rather than declared in a header and defined in a matching .cpp file.
Coding Challenges
Write a function template min_value(T a, T b) returning the smaller of two values, and call it with two ints and two doubles, printing both results.
📄 View solutionWrite a class template Pair
Explain precisely what monomorphization means, and why calling max_value with both int and double arguments in the same program results in genuinely two separate compiled functions rather than one generic function handling both cases at runtime.
📄 View solutionChapter 1 Quick Reference
template<typename T>— declares a function or class template- Monomorphization — one fully concrete, type-checked copy generated per distinct type actually used, zero runtime overhead
- A direct parallel to Rust's own generics — the identical compilation strategy
std::vector<int>is literally a class template instantiation, not a special built-in- Template errors surface at the instantiation site — often confusing pre-C++20; concepts (
cpp3-2) improve this - Template definitions usually live entirely in headers, not split across a .cpp file
- Next chapter: the STL's containers — finally resolving C's own "no standard containers" gap