Shiklo Tools
PDF40
Image20
Calculators & Converters25
Text & Writing13
Developer26
Video14
Audio14
Document14
Data & Spreadsheet12
Web & SEO9
OCR & Scanning5
Archive & File12
Security & Privacy23
Health & Medical29
QR & Barcode5

C++ Templates

A template is a recipe for code that works with any type. Instead of writing maxInt, maxDouble and maxString, you write one template and the compiler makes a version for every type you use it with. The whole standard library is built on templates: std::vector<int> and std::vector<std::string> come from one vector template.

Function templates

#include <iostream>
#include <string>
#include <vector>

template <typename T>
T largest(const std::vector<T>& v) {
    T best = v[0];
    for (const T& x : v) {
        if (best < x) best = x;
    }
    return best;
}

int main() {
    std::vector<int> nums = {42, 7, 19, 88, 3};
    std::vector<std::string> words = {"pear", "apple", "mango"};
    std::cout << largest(nums) << "\n";
    std::cout << largest(words) << "\n";
    return 0;
}
Output
88
pear

template <typename T> says that T stands for a type filled in later. The compiler deduces T from the argument: int for nums, std::string for words. The only thing largest needs from T is that two values can be compared with <.

Class templates

#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

template <typename T>
class Stack {
    std::vector<T> items;
public:
    void push(const T& x) { items.push_back(x); }
    T pop() {
        if (items.empty()) throw std::out_of_range("pop from an empty stack");
        T x = items.back();
        items.pop_back();
        return x;
    }
    bool empty() const { return items.empty(); }
    std::size_t size() const { return items.size(); }
};

int main() {
    Stack<int> numbers;
    numbers.push(1);
    numbers.push(2);
    Stack<std::string> names;
    names.push("first");
    names.push("second");
    std::cout << numbers.pop() << " " << names.pop() << " " << names.size() << "\n";
    return 0;
}
Output
2 second 1

For a class template, the type is written in angle brackets: Stack<int>.

Concepts (C++20)

When a template is used with a type that does not fit, the error messages can be long and confusing. C++20 concepts state the requirements up front, so the error is short and clear:

#include <concepts>
#include <iostream>

template <std::integral T>
T sumTo(T n) {
    T total = 0;
    for (T i = 1; i <= n; i++) total += i;
    return total;
}

int main() {
    std::cout << sumTo(100) << "\n";
    std::cout << sumTo(10LL) << "\n";
    return 0;
}
Output
5050
55

sumTo(2.5) now fails with a message saying double does not satisfy std::integral.

Where templates live

The compiler must see a template's full code wherever it is used, so templates are written entirely in header files, not split into a declaration and a .cpp definition like ordinary functions.

Common mistakes

  • With template <typename T> T maxOf(T a, T b), the call maxOf(3, 4.5) does not compile: T cannot be int and double at once. Write maxOf<double>(3, 4.5) to choose the type yourself.
  • Error messages from templates can be long. Read the first error line: it names the type that does not support the operation you used.

Practice exercises

  1. Write a template swapValues(T& a, T& b) and use it with int and std::string.
  2. Write a template average for a vector of any number type.
  3. Write a class template Pair<A, B> with two members and a method that prints them.