Skip to content
Templates Introduction
step 1/7

Reading — step 1 of 7

Learn

~2 min readClasses, Inheritance, and Templates

Templates are how C++ does generic programming — write code once, the compiler generates specialized versions for each type used. The STL is built on templates: std::vector<int>, std::vector<std::string>, std::map<K, V> are all template instantiations.

Function templates

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

std::cout << max_of(3, 7);              // T = int → 7
std::cout << max_of(3.14, 2.71);         // T = double → 3.14
std::cout << max_of<std::string>("a", "b");  // T = std::string → "b"

template <typename T> declares the type parameter. T is then used like any type. The compiler instantiates a fresh function for each unique T you call with.

typename and class are interchangeable here: template <class T> works too. Modern style prefers typename.

Multiple type parameters

template <typename A, typename B>
auto add(A a, B b) {
    return a + b;     // return type deduced — could be A, B, or something promoted
}

add(3, 2.5);    // int + double → double

Class templates

template <typename T>
class Box {
    T value;
public:
    Box(T v) : value{std::move(v)} {}
    T get() const { return value; }
    void set(T v) { value = std::move(v); }
};

Box<int> b1{42};
Box<std::string> b2{"hello"};

When you write Box<int>, the compiler stamps out a class with T replaced by int. Two instantiations of the same template are DIFFERENT TYPES — you can't assign a Box<int> to a Box<double>.

Templates are compiled per-instantiation

Unlike Java/C# generics (one bytecode, runtime erasure) or Rust (one binary, monomorphized at link), C++ templates are compiled FRESH every time you use them with a new type. Consequences:

  • Type errors only surface AT THE INSTANTIATION POINT — error messages mention deep template internals.
  • Templates must be defined in HEADERS so every translation unit can instantiate them. Putting template implementations in .cpp files breaks links.
  • Code bloat is real — std::vector<int> and std::vector<std::string> are completely separate code in the binary.

Type traits and concepts (briefly)

C++20 added concepts — constraints on template parameters:

#include <concepts>

template <std::integral T>     // T must be an integer type
T add_one(T n) { return n + 1; }

add_one(5);        // OK
add_one(3.14);     // compile error — double doesn't satisfy integral

Without concepts, you used static_assert(std::is_integral_v<T>) or SFINAE — far more painful. Concepts give clearer errors and clearer intent.

GCC 9.2 (the version on Judge0) doesn't fully support concepts — you'd see them in newer code (GCC 10+).

Common mistakes

  • Putting template definitions in .cpp files — linker errors. Keep them in headers.
  • Confusing typename keyword inside templatestypename T::value_type x; tells the compiler the dependent name is a type, not a value.
  • Assuming all instantiations share state — they don't. Counter<int>::count and Counter<double>::count are different statics.
  • Cryptic error messages — read past the template gibberish to find the actual constraint that failed (the source line of YOUR code, not the library's).

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…