Skip to content

Intermediate · Templates, smart pointers and move semantics · topic 26 of 42 · 35 min

Templates: code for any type

Explanation

A template is a blueprint for a function or class with a type left as a parameter, written template <typename T>. The compiler generates a real version for each type you use, at compile time, so there is no run-time cost. The whole STL (vector<T>, map<K, V>, sort) is built from templates. C++20 concepts let you state what a type must support.

Why templates?

Suppose you write int largest(int a, int b). Tomorrow you need it for double, then for std::string. Copying the function for every type is boring and error-prone. A template lets you write the logic once, with the type as a parameter. This style is called generic programming.

cpp
#include <iostream>
#include <string>

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

int main() {
    std::cout << largest(3, 9) << '\n';                                     // 9 (T = int)
    std::cout << largest(2.5, 1.5) << '\n';                                 // 2.5 (T = double)
    std::cout << largest(std::string("apple"), std::string("mango")) << '\n';   // mango
    // largest(3, 2.5);   // error: T cannot be both int and double
    std::cout << largest<double>(3, 2.5) << '\n';                           // 3, T given explicitly
}
The compiler deduces T from the arguments. Each different T creates a separate function (this is called instantiation).
Think of it like this: A template is like a cake mould. The mould (template) is made once. Pour in chocolate batter and you get a chocolate cake; pour in vanilla and you get a vanilla cake. Each cake is a real, separate thing made from the same shape, and the shaping happens before serving (at compile time).

Class templates

cpp
template <typename T>
class Box {
public:
    explicit Box(T value) : value_(value) {}
    const T& get() const { return value_; }
private:
    T value_;
};

template <typename K, typename V>
struct Entry {
    K key;
    V value;
};

Box<int> b1(42);
Box<std::string> b2("parcel");
Box b3(3.5);                     // C++17: the compiler deduces Box<double>
Entry<std::string, int> e{"rice", 40};
std::vector<int> is exactly this: a class template vector instantiated with T = int.

Non-type template parameters

cpp
template <typename T, std::size_t N>
std::size_t lengthOf(const T (&)[N]) { return N; }

int marks[7] = {};
std::cout << lengthOf(marks) << '\n';   // 7
Template parameters can also be values known at compile time, like the N in std::array<int, N>.

Templates live in headers

The compiler needs to see the full template body at the point where it creates a new version (for example largest<double>). That is why templates are almost always written entirely in header files, not split into .h and .cpp. Putting the body in a .cpp file usually gives "undefined reference" linker errors.

C++20 concepts: saying what T must support

cpp
#include <concepts>

template <typename T>
concept Number = std::integral<T> || std::floating_point<T>;

template <Number T>
T average(T a, T b) { return (a + b) / 2; }

// average(4, 6) == 5;  average(std::string("a"), std::string("b")) -> clear error: constraints not satisfied
auto twice(std::integral auto x) { return x * 2; }   // abbreviated form
A concept is a named compile-time requirement. Without it, misuse gives pages of confusing errors from deep inside the template.

Before concepts, template error messages were famous for being hundreds of lines long. A concept checks the requirement at the call and reports one clear message like "the associated constraints are not satisfied".

Common mistakes

  • Mixing argument types so T cannot be deduced (largest(3, 2.5)). Convert one argument or write largest<double>(...).
  • Writing a template body in a .cpp file and getting linker errors.
  • Assuming T supports an operation (like > or +) that it does not. Use a concept to make the requirement explicit.
  • Over-using templates for code that only ever handles one type. Generic code is harder to read; use it when it truly pays off.
Tip: Templates are a "zero-cost abstraction": std::sort on ints is as fast as a hand-written int sort, often faster than C's qsort, because the comparison can be inlined for the exact type.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Templates: code for any type · 1/6

Templates

Templates let you write a function or class once and use it with many types.

Prefer a video by a teacher? Find free videos on “c++ templates function template class template concepts tutorial” on YouTube ↗

In real life: A generic "top N" function for dashboards

An analytics dashboard shows the top 5 products by sales, the top 5 cities by orders and the top 5 riders by ratings. One function template topN works for all three, whatever the item type, as long as you pass a way to compare them.

cpp
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

template <typename T, typename Compare>
std::vector<T> topN(std::vector<T> items, std::size_t n, Compare better) {
    std::sort(items.begin(), items.end(), better);
    if (items.size() > n) items.resize(n);
    return items;
}

int main() {
    std::vector<int> sales = {120, 450, 90, 300, 610};
    for (int s : topN(sales, 3, [](int a, int b) { return a > b; })) std::cout << s << ' ';
    std::cout << '\n';   // 610 450 300

    std::vector<std::string> cities = {"Pune", "Agra", "Kochi"};
    for (const auto& c : topN(cities, 2, [](const std::string& a, const std::string& b) { return a < b; })) std::cout << c << ' ';
    std::cout << '\n';   // Agra Kochi
}
One template, many types; the comparator decides what "top" means.

Practice (0/4 done)

Task 1 · Question

template <typename T> T add(T a, T b) { return a + b; } What is add(2, 3)?

Task 2 · Question

Why does add(2, 3.5) fail to compile with the template above?

Task 3 · Question

You put a template function's body in utils.cpp and only its declaration in utils.h. Other files call it with new types. What usually happens?

Task 4 · Practice

Write a class template Stack<T> using a std::vector<T> inside, with push, pop, top and empty. Then write a function template printAll that prints every element of any std::vector<T>. Test Stack<int> and Stack<std::string>.

Quick quiz

Question 1

1.When are templates turned into real code?

Question 2

2.Which standard library type is a class template?

Question 3

3.What does a C++20 concept do?

Question 4

4.Box b(3.5); compiles in C++17 because of…

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

When are templates turned into real code?

Answer: At compile time, when used with specific types

Instantiation happens during compilation.

Which standard library type is a class template?

Answer: std::vector

std::vector<T> is a class template; int, double and char are built-in types.

What does a C++20 concept do?

Answer: States compile-time requirements on template arguments, giving clearer errors

Concepts constrain templates and improve error messages.

Box b(3.5); compiles in C++17 because of…

Answer: class template argument deduction (CTAD)

CTAD deduces Box<double> from the constructor argument.

Which is a valid C++20 designated initialiser for struct P { int x; int y; };?Related

Answer: P p{.x = 1, .y = 2};

Designators use .name and must follow the declaration order.

From C++20 ranges, views and other C++20 essentials

Which include style is used for your own header file?Related

Answer: #include "myfile.h"

Quotes search your project folder first; angle brackets are for standard and system headers.

From Functions: declare, define, call and return

What is the template method pattern?Related

Answer: A fixed sequence of steps in a parent, with some steps filled in by subclasses

The parent owns the flow.

From Abstract classes

A hosts template using hostvars fails with an undefined variable when run with --limit web01. Why?Related

Answer: Facts for the other hosts were not gathered in this run

Gather facts for all hosts first.

From Jinja2 templates

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Templates, smart pointers and move semantics” before its exam: Smart pointers 1: std::unique_ptr, Smart pointers 2: std::shared_ptr and std::weak_ptr, Move semantics: steal instead of copy.
  2. Module 7 exam: Templates, smart pointers and move semantics · 12 questions · 25 min, without help. 4 topics of this module still to finish first.
  3. Then the next module, Modern C++: lambdas, C++17 and C++20 essentials. 42 topics left in the course before the final exam.

← Previous: STL algorithms: sort, find, count, accumulate and binary search