Imagine writing a function that returns the larger of two numbers. You write it for int, then you need it for double, then for string. The three versions are identical except for the type. Copying code like that is tedious and error-prone, and templates remove the need for it.
A template is a blueprint for a function or class with one or more type parameters. You write the code once, using a placeholder such as T for the type, and the compiler generates a real version for each type you use it with. This style is called generic programming, and it's one of the features that makes C++ both flexible and fast.
You've already been using templates: vector<int>, map<string, double> and unique_ptr<Player> are all class templates from the standard library. In this lesson you'll write your own function and class templates, understand what happens behind the scenes and learn how C++20 concepts make template errors readable.
Function templates
template <typename T>
T biggest(T a, T b) {
return (a > b) ? a : b;
}
biggest(3, 9); // T is int
biggest(2.5, 1.5); // T is double
biggest<string>("pear", "apple");template <typename T>introduces a type parameter calledT. (classcan be used instead oftypename; they mean the same here.)- The compiler usually deduces
Tfrom the arguments. You can also name it explicitly in angle brackets. - Both arguments must have the same type for
Tto be deduced:biggest(3, 2.5)fails becauseTcan't be bothintanddouble.
How templates work
A template isn't compiled on its own. When you call biggest(3, 9), the compiler instantiates a version where every T becomes int, and compiles that. Each type gets its own efficient, fully typed code, with no run-time cost compared with writing the versions by hand.
The code inside the template must make sense for every type you use. biggest needs > to work, so it's fine for numbers and strings but fails to compile for a struct without a > operator. Because templates are instantiated where they're used, their full definitions usually live in header files.
Class templates
A class can be a template too. Here's a small box that holds any type:
template <typename T>
class Box {
T value;
public:
Box(T v) : value(v) {}
T get() const { return value; }
};
Box<int> a(5);
Box<string> b("hello");Templates can have several parameters, as in template <typename K, typename V>, which is exactly how std::map<K, V> is declared. Since C++17 the compiler can often deduce class template arguments too, so Box c(3.5); creates a Box<double>.
auto, constexpr and concepts
auto asks the compiler to deduce a variable's type from its value, which is especially handy with long template types: auto it = prices.find("Pen");. Function parameters can even be auto in C++20, a shorthand for a template.
constexpr marks values and functions that can be computed at compile time, such as constexpr int MAX = 100;, which is a natural partner for templates.
Template errors used to be famously long and confusing. C++20 concepts let you state what a type must support, and the compiler reports a short, clear message if it doesn't:
#include <concepts>
template <std::totally_ordered T>
T biggest(T a, T b) { return (a > b) ? a : b; }C++ Templates Syntax
Template syntax
template <typename T>
T functionName(T a, T b) { ... }
template <typename K, typename V>
class Pair {
K key;
V value;
public:
Pair(K k, V v) : key(k), value(v) {}
};
functionName(1, 2);
functionName<double>(1, 2.5);
Pair<string, int> p("age", 15);C++ Templates Summary
template <typename T>writes a function or class once for many types.- The compiler deduces
Tfrom arguments, or you can give it:f<int>(...). - Each type used creates its own instantiated, fully typed version at compile time.
- Class templates like
Box<T>,vector<T>andmap<K, V>take type parameters in angle brackets. autodeduces types; C++20 concepts state requirements and give clearer errors.
C++ Templates Examples
Each example shows the code, the output it produces and what each part does.
One function, many types
#include <iostream>
#include <string>
using namespace std;
template <typename T>
T biggest(T a, T b) {
return (a > b) ? a : b;
}
int main() {
cout << biggest(3, 9) << endl;
cout << biggest(2.5, 1.5) << endl;
cout << biggest<string>("pear", "apple") << endl;
cout << biggest<double>(3, 2.5) << endl;
return 0;
}9
2.5
pear
3Line-by-line explanation
- Lines 5 to 8The template is written once with the placeholder T.
- Lines 11 to 12T is deduced as int, then double.
- Line 13Naming string makes the text literals compare as strings, alphabetically.
- Line 14Naming double lets an int and a double be compared.
A function template over containers
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <typename T>
T total(const vector<T>& items) {
T sum{};
for (const T& x : items) sum += x;
return sum;
}
int main() {
vector<int> scores = {72, 95, 61};
vector<double> prices = {1.20, 3.50, 24.50};
vector<string> parts = {"Code", "vra"};
cout << total(scores) << endl;
cout << total(prices) << endl;
cout << total(parts) << endl;
return 0;
}228
29.2
CodevraLine-by-line explanation
- Line 8T sum{} starts at 0 for numbers and an empty string for strings.
- Line 9+= adds numbers and joins strings, so the same template works for both.
- Lines 18 to 20Three different instantiations from one template.
A class template
#include <iostream>
#include <string>
#include <vector>
using namespace std;
template <typename T>
class Stack {
vector<T> items;
public:
void push(const T& x) { items.push_back(x); }
T pop() {
T top = items.back();
items.pop_back();
return top;
}
bool empty() const { return items.empty(); }
size_t size() const { return items.size(); }
};
int main() {
Stack<string> history;
history.push("home");
history.push("shop");
history.push("checkout");
cout << "Pages: " << history.size() << endl;
while (!history.empty()) {
cout << "Back from " << history.pop() << endl;
}
return 0;
}Pages: 3
Back from checkout
Back from shop
Back from homeLine-by-line explanation
- Lines 6 to 18A stack (last in, first out) that works for any type, built on a vector.
- Line 21Stack<string> creates a version for strings; Stack<int> would work just as well.
- Lines 27 to 29Items come back out in reverse order, like a browser's back button.
Common C++ Templates Mistakes
Mixing types the template can't deduce
biggest(3, 2.5); // error: T deduced as both int and doublebiggest<double>(3, 2.5);Using a type that lacks a required operation
struct Point { int x, y; };
biggest(Point{1, 2}, Point{3, 4}); // error: no operator> for Pointstruct Point {
int x, y;
bool operator>(const Point& o) const { return x > o.x; }
};Every operation the template uses must exist for the type you pass in.
Defining templates only in a .cpp file
// box.h declares the template, box.cpp defines it
// main.cpp: Box<int> b(1); -> linker error// box.h: declare AND define the template in the headerThe compiler needs the full template wherever it's used, so template code lives in headers.
C++ Templates in Real Projects
Templates in real C++
The entire Standard Template Library, from vector and map to sort and unique_ptr, is built from templates. Game engines use them for maths types such as Vector3<float>, and libraries like Eigen use templates to generate extremely fast numerical code. Understanding templates makes the STL's documentation and error messages much easier to read.
C++ Templates FAQ
What is template specialisation in C++?
A specialisation gives a template a different implementation for one particular type. After the general template <typename T> string describe(T), writing template <> string describe<bool>(bool b) { ... } makes calls with a bool use the special version, while every other type uses the general one. For functions, an ordinary overload is often simpler; specialisation is used more for class templates.
Can a template parameter be a number instead of a type?
Yes. A non-type template parameter such as template <typename T, int N> takes a value known at compile time. That's how std::array<int, 5> works: the size is part of the type, so it costs nothing at run time and arrays of different sizes are different types. The value must be a constant, such as a literal or a constexpr variable.
What is a variadic template?
A template that accepts any number of arguments, written with ...: template <typename... Ts> auto sum(Ts... xs) { return (xs + ...); }. The (xs + ...) is a C++17 fold expression, which applies + across every argument, so sum(1, 2, 3.5) gives 6.5. Functions like std::make_unique use variadic templates to pass any constructor arguments through.
Do templates make programs bigger or slower?
Not slower: the compiler writes a separate, fully typed version for each type you use, so the code runs as fast as if you'd written it by hand. Each of those versions takes space, though, so using a large template with many different types can make the executable bigger and compilation slower. In everyday programs the effect is small.
Can a member function template be virtual?
No. g++ reports "templates may not be 'virtual'", because a virtual function needs a single entry in the class's table of virtual functions, and a template could produce any number of versions. If you need both, make the virtual function take a fixed type, or keep the template non-virtual and have it call a virtual function internally.
C++ Templates Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Complete the line that starts a function template.
< T>
T twice(T x) { return x + x; }
What does this print?
template <typename T>
T twice(T x) { return x + x; }
// in main:
cout << twice(4) << " " << twice(string("ab"));
What happens when you call a function template with a new type?
What does this print?
template <typename T>
class Box {
T v;
public:
Box(T x) : v(x) {}
T get() const { return v; }
};
// in main:
Box<double> b(7);
cout << b.get() / 2;
Why are templates usually defined in header files?
C++ Templates Quiz
5 questions to check what you learned.
What problem do templates solve?
- Slow programs
- Writing the same function or class again for different types
- Memory leaks
- Reading files
Which of these is a class template?
- std::vector
- int
- cout
- main
How do you explicitly choose the type for a function template?
- f(int, 3, 4)
- f(3, 4)<int>
- int f(3, 4)
- f<int>(3, 4)
What do C++20 concepts do?
- Replace classes
- Run templates at run time
- Describe requirements for template types and give clearer errors
- Remove the need for typename
Is there a run-time cost to using a function template compared with hand-written versions?
- Yes, templates are always slower
- No, each instantiation is ordinary compiled code for its type
- Only for strings
- Only in debug builds