latency.lab
Module 09

Templates & Generics

Level: advancedTime: ~2 hrsPrereq: Module 08

By the end you can

Templates are how C++ achieves zero-cost generic code. std::vector<int> and std::vector<Order> are generated from one template, each specialized and optimized at compile time. No boxing, no runtime dispatch — the generic code compiles down to code as tight as if you'd written it by hand.

Function templates

fntemplate.cpp
template <typename T>
T max_of(T a, T b) {
    return (a > b) ? a : b;
}

auto a = max_of(3, 7);       // T deduced as int
auto b = max_of(2.5, 1.1);   // T deduced as double

The compiler instantiates a separate version of the function for each type you use it with. T is deduced from the arguments — you rarely specify it explicitly.

Class templates

classtemplate.cpp
template <typename T>
class Stack {
public:
    void push(const T& v) { data_.push_back(v); }
    T pop() { T v = data_.back(); data_.pop_back(); return v; }
    bool empty() const { return data_.empty(); }
private:
    std::vector<T> data_;
};

Stack<int> s;         // a stack of ints
Stack<std::string> ss; // a stack of strings, generated from the same template
Why templates live in headers

The compiler needs the full template definition to instantiate it for a given type, and instantiation happens in whatever .cpp uses the template. So template definitions go in header files, not split into .cpp like normal functions. Putting a template's body in a .cpp is the classic "undefined reference" for templates.

auto and deduction

auto asks the compiler to deduce a variable's type, using the same rules as template deduction. Use it to avoid repeating long type names (especially iterators) — but don't overuse it where an explicit type aids clarity.

auto.cpp
auto it = v.begin();               // instead of std::vector<Order>::iterator
for (const auto& order : book)     // const ref: no copy, read-only
    process(order);

A taste of metaprogramming

Templates can compute at compile time. You don't need to master this for interviews, but recognizing it helps you read library code.

meta.cpp
// compile-time factorial via recursion
template <int N>
struct Factorial { static constexpr int value = N * Factorial<N-1>::value; };
template <>
struct Factorial<0> { static constexpr int value = 1; };

constexpr int f = Factorial<5>::value;  // computed at compile time = 120
Modern shortcut

Today you'd write compile-time computation with constexpr functions, which read like normal code but run at compile time. And C++20 concepts make template requirements readable and error messages sane. Know they exist; you can go deep later.

Build

Exercise 09.1 — Generic containers

  • Write the generic Stack<T> above and use it with int, std::string, and your own Order type.
  • Write a function template template<typename It> auto sum(It begin, It end) that works on any iterator range and returns the total. Test it on a vector and a list.
  • Deliberately put a template's definition in a .cpp file, call it from main.cpp, and watch the linker error. Then move it to a header and watch it link. Now you'll never be confused by that error again.

Takeaways

  • Templates generate specialized, zero-overhead code per type at compile time (instantiation).
  • Template argument deduction usually infers T from the arguments.
  • Template definitions belong in headers, because instantiation needs the full body.
  • auto uses the same deduction rules; great for iterators, use with judgment.
  • constexpr (and C++20 concepts) are the modern tools for compile-time work and constraints.
Live

Loading starter code…

Checkpoint · Templates

6 questions · pass at 70%

Q01
What does "template instantiation" mean?
WhyFor each set of template arguments, the compiler generates a separate specialized version at compile time — hence zero runtime overhead.
Q02
Why must template definitions usually go in header files?
WhyInstantiation happens where the template is used. If the body is hidden in a .cpp, other files can't instantiate it, producing linker errors. Definitions go in headers.
Q03
In max_of(3, 7), how is T determined?
WhyTemplate argument deduction infers T from the call arguments; here both are int, so T = int.
Q04
auto deduces a variable's type using:
Whyauto follows template deduction rules. It is especially handy for verbose iterator types.
Q05
What is the runtime cost of using a class template like std::vector versus a hand-written int array class?
WhyTemplates are resolved at compile time and specialized per type, so generic C++ compiles to code as efficient as a hand-written equivalent.
Q06
The modern, readable way to do compile-time computation is:
Whyconstexpr functions read like ordinary code but evaluate at compile time, replacing most old template-metaprogramming tricks.

Finished Module 09?

Pass the quiz to complete it automatically.

+ Note