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
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 doubleThe 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
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 templateThe 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 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.
// 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 = 120Today 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.
Exercise 09.1 — Generic containers
- Write the generic
Stack<T>above and use it withint,std::string, and your ownOrdertype. - 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
.cppfile, call it frommain.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
Tfrom the arguments. - Template definitions belong in headers, because instantiation needs the full body.
autouses 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.
Loading starter code…
Checkpoint · Templates
6 questions · pass at 70%
max_of(3, 7), how is T determined?auto deduces a variable's type using:Finished Module 09?
Pass the quiz to complete it automatically.