Templates — function & class templates

RoadmapsC++

Scenario

You write a math library with an `add(int, int)` function. Then users ask for float support, so you write `add(float, float)`. Then they ask for `double`. You now have 10 identical functions with different types.

How can you write the logic once and let the compiler generate the 10 variations automatically?

Mental model

A template is a cookie cutter. A cookie cutter is not a cookie; you cannot eat it. It only becomes a cookie when you press it into dough (instantiate it with a concrete type like `int`).

Templates allow you to write Generic Code. Instead of specifying concrete types, you use a placeholder `T`. The compiler acts as a code generator: whenever it sees you call the function with a new type, it literally copy-pastes your template, replaces `T` with that type, and compiles the newly generated code.

Explanation

**Function Templates:**

Defined using `template <typename T>`. When you call `add(5, 10)`, the compiler deduces `T` is `int` and generates `int add(int, int)`. If you call `add(5.5, 2.0)`, it generates a separate `double add(double, double)` function.

**Class Templates:**

Used for generic data structures (like `std::vector<T>`). Unlike functions, class templates usually require you to explicitly specify the type when instantiating: `Box<int> b;`.

**The Template Compilation Model:**

Because the compiler needs to generate the concrete code *at the exact moment* you instantiate the template, **the entire template definition must be visible in the header file**. You cannot put the implementation of a template in a `.cpp` file (unless you explicitly instantiate every type you plan to use, which defeats the purpose). If you try, you will get notorious "Undefined Reference" Linker Errors.

**Real-world Engineering:**

Templates are the foundation of the STL (Standard Template Library). They provide zero-overhead abstractions because the generated code is completely type-safe and perfectly optimized for that specific type, unlike Java generics which use type erasure at runtime (C# preserves them, but with a different mechanism).

**Template Type Deduction:**

When calling a template function, the compiler deduces the type based on the arguments. This deduction is strict. If you call `add(5.0, 10)` (a `double` and an `int`), the compiler fails to deduce a single `T` and throws an error. You must either cast one argument, or explicitly specify the type: `add<double>(5.0, 10)`.

Code examples

Function and Class Templates

#include <iostream>
#include <string>

// Function Template
template <typename T>
T add(T a, T b) {
    return a + b;
}

// Class Template
template <typename T>
class Box {
private:
    T contents;
public:
    Box(T val) : contents(val) {}
    T get() { return contents; }
};

int main() {
    // Compiler generates int version
    std::cout << add(5, 10) << '\n'; 
    
    // Compiler generates double version
    std::cout << add(5.5, 2.2) << '\n';
    
    // Explicitly instantiating a class template
    Box<std::string> stringBox("Hello Template");
    std::cout << stringBox.get() << '\n';
    
    return 0;
}

The source code only contains one `add` function, but the compiled binary will contain two distinct functions.

Key points

Common mistakes

Recall questions

Questions & answers

A developer writes `template <typename T> T max(T a, T b) { return a > b ? a : b; }`. They call it with `max(5.0, 10)`. The compiler throws an error. Why?

Template Type Deduction failure. The first argument is a `double`, and the second is an `int`. The compiler cannot deduce a single type for `T`. You must either explicitly cast one argument, or explicitly specify the type: `max<double>(5.0, 10)`.

Approach: Understand how strict template type deduction is compared to normal implicit conversions.

You write a template class in `MyContainer.h` and implement its methods in `MyContainer.cpp`. When you try to use `MyContainer<int>` in `main.cpp`, you get Linker errors (Undefined Reference). What went wrong?

The compiler compiles `.cpp` files individually. When it compiled `MyContainer.cpp`, it didn't know you needed an `<int>` version, so it generated nothing. When linking `main.cpp`, the `<int>` version didn't exist. Template implementations must be placed in the header file.

Approach: Identify the root cause of the most common compilation error in C++ templates.

Continue learning

Previous: Classes, constructors, destructors & this

Return to C++ Roadmap