Skip to content

Module 12 — Summary

The essentials

  • A template is a pattern, not a type. The compiler generates a concrete function or class for each set of arguments it is used with, at compile time, with no run-time cost — which is also why it works for int, and why it cannot grow after the program is compiled.
  • Templates are checked twice: syntax and non-dependent names when the definition is read, everything involving T at instantiation. That is why errors arrive late, and why "it compiles" means very little until it is instantiated for the types you intend to use.
  • The definition must be visible where the type is used, so template code normally lives in a header. The alternative — a .cpp plus explicit instantiations — trades flexibility for build time, and makes each new type a deliberate decision.
  • Every template imposes requirements, whether or not anybody wrote them down. The error for a type that fails is the requirement surfacing, and it is always about your type.
  • Document the requirements, and enforce what can be enforced. A static_assert with a message turns a page of diagnostics into one line that names the requirement and the alternative.
  • typename is required for a dependent type name (typename T::value_type), because until T is known the compiler cannot tell a type from a static value.
  • Non-type parameters make a value part of the type. A capacity known at compile time gives storage inside the object, checks at compile time, and an error the moment the value comes from configuration instead.
  • Specialise for correctness, not for convenience. Formatter<bool> fixes a real defect; the standard library's std::vector<bool> trades addressability for memory and is still argued about. if constexpr branches inside one implementation, and the branch not taken is discarded.
  • Compile-time and run-time polymorphism trade differently. Templates avoid dispatch and extend only by recompiling; virtual interfaces dispatch and can be extended by code written later. The question is whether the type is a fact about the design or something the program discovers.
  • Read a template error from the end, find the frame naming your own file, then reduce it to five lines. In generic code, reduction is not a debugging step — it is the method.
  • Generalise when the second genuine use appears, not in anticipation. Two callers are evidence; "we might need it" is a cost with no benefit.

The one-sentence version

Write the code once in terms of a type you do not know yet, state what that type must provide, and let the compiler generate — and check — a real version for every type that actually gets used.

Terms you must now be able to define

template · function template · class template · template parameter · type parameter · non-type parameter · deduction · instantiation · explicit instantiation · dependent name · typename · requirement · static_assert · type trait · if constexpr · full specialisation · partial specialisation · class template argument deduction · code bloat · generic programming

All of them are defined in the glossary under this module.

Before you move on

  • [ ] All core exercises attempted, with the results checked
  • [ ] The lab builds with no warnings and passes its checklist
  • [ ] The requirement failure was forced on purpose, captured, and reduced to five lines
  • [ ] The repository was instantiated for two unrelated types
  • [ ] Quiz score ≥ 80%, and every miss explained
  • [ ] At least one challenge problem attempted — including the argument against generalising
  • [ ] Skills checklist ticked, with the evidence for each item
  • [ ] I can read a template diagnostic and find the sentence that is about my type

Where this goes next

Module 13 — Exception Handling is the next thing your generic components need. A Repository<T> part-way through an operation that throws must be left in a known state, and that is what exception-safety guarantees are for; the code that satisfies them is built from Module 11's ownership and this module's genericity. Lab 11 previewed throw as a mechanism; Module 13 makes failure a designed part of the system.

Module 14 — The STL with OOP is this module applied. Every container and algorithm there is a template, every one of them states its requirements, and the errors you will meet are exactly the ones this module taught you to read. If the last line of a diagnostic still looks like noise, Module 14 will feel like a list of names; if it reads as a sentence about your type, Module 14 is where the rest of the standard library becomes usable.

Further reading

  • Effective Modern C++, Scott Meyers — practical template reasoning, deduction, and why some template code is best avoided.
  • The C++ Programming Language (4th ed.), Bjarne Stroustrup — templates in depth, and the argument for why they are the basis of the standard library.
  • cppreference: templates — the language reference, including the exact rules for deduction and the requirement lists of every standard algorithm.
  • Modern C++ Design, Andrei Alexandrescu — only if you want to go well beyond this module; it assumes the material here is already comfortable, and it is the source of the techniques that produced std::function and std::tuple.

See Further Reading for the full list, with what each source is good for and when to reach for it.