Templates

Course 2 · Ch 1
Templates
The exact strategy Rust's own generics use — another rare point of real convergence

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

template<typename T> T max_value(T a, T b) { return (a > b) ? a : b; } max_value(3, 7); // T deduced as int max_value(2.5, 1.1); // T deduced as double

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

template<typename T> class Box { public: T value; Box(T v) : value(v) {} }; Box<int> b(42);

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.

ConceptCC++ TemplatesRust Generics
Generic codevoid* + manual casting, or macros — no type safetytemplates — fully type-checkedgenerics — fully type-checked
Compilation strategyn/amonomorphization — one concrete copy per type usedmonomorphization — the same strategy
Runtime overheadn/anonenone
Templates are entirely a compile-time concept
There's no such thing as a "template object" existing at runtime — only the fully concrete, monomorphized functions and classes the compiler actually generates from each distinct instantiation.
Template code usually lives in headers, not separate .cpp files
A genuine, structural exception to 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

Challenge 1

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 solution
Challenge 2

Write a class template Pair holding two values of the same type, with a method sum() that adds them together. Instantiate it once with int and once with double, printing both results.

📄 View solution
Challenge 3

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 solution

Chapter 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