CppTemplates Introduction

Templates Introduction

A template is a blueprint for generating code. Instead of writing a separate function or class for every type you need to support, you write the logic once, using a placeholder for the type, and let the compiler generate the real, type-specific version for you whenever it's actually used. This is the foundation of generic programming in C++, and it's the mechanism behind the entire Standard Template Library (STL) — every std::vector, std::map, and std::sort you've used is built with templates.
The problem templates solve
Imagine you need a function that returns the larger of two values, and you need it to work for int, double, and std::string. Without templates, you'd have to write (or rely on function overloading to provide) a separate function for every type:

without_templates.cpp

CPP
#include <string>

int maxInt(int a, int b) {
    return (a > b) ? a : b;
}

double maxDouble(double a, double b) {
    return (a > b) ? a : b;
}

std::string maxString(std::string a, std::string b) {
    return (a > b) ? a : b;
}

// ...and one more overload for every new type you need.
Function overloading lets you reuse the name max for each of these, but you're still writing (and maintaining) the identical body over and over — once per type. If you find a bug in the logic, you have to fix it in every copy. Templates remove that duplication entirely: you write the logic once, generically, and the compiler produces the type-specific versions for you.

with_templates.cpp

CPP
#include <iostream>
#include <string>

template <typename T>
T maxValue(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    std::cout << maxValue(3, 5) << std::endl;          // int
    std::cout << maxValue(2.5, 1.1) << std::endl;      // double
    std::cout << maxValue(std::string("cat"),
                           std::string("dog")) << std::endl; // string
    return 0;
}
Compile-time, not runtime
Templates are resolved entirely at compile time. When the compiler sees maxValue(3, 5), it generates a real function called something like maxValue<int> with T replaced by int, compiles it as if you'd written it by hand, and calls that. This process is called template instantiation. There is no type information carried around at runtime, and no performance penalty compared to hand-written type-specific code.
A real trade-off: compile time and binary size
Because the compiler generates a brand-new copy of a template for every distinct type it's used with, heavy template use can noticeably increase compile times and binary size — this is sometimes called code bloat. Ten different instantiations of the same class template mean ten separate copies of machine code. This is a genuine cost of generic programming in C++, and it's one reason template-heavy code (like much of the STL) tends to live entirely in header files.
Templates vs. function overloading

It's worth being clear about how these two features differ, since they solve related problems in different ways.

Aspect

Function Overloading

Templates

Code written

One version per type, by hand

One generic version, compiler generates the rest

Adding a new type

Requires writing a new overload

Works automatically if the type supports the operations used

Behavior per type

Can differ completely between overloads

Same logic for every type (unless specialized)

Resolved

Compile time (best match chosen)

Compile time (instantiated per type used)

What's ahead
  • Function templates — generic functions like the maxValue example above.

  • Class templates — generic classes and containers, like a Box<T> you design yourself.

  • Template specialization — providing a custom implementation for one specific type.

  • Variadic templates — templates that accept any number of type parameters.

  • Concepts (C++20) — constraining what types a template will accept, with clear error messages.