A template is a blueprint the compiler stamps out for each set of types you use it with. Write the algorithm once; get type-checked, fully optimised code for every type.
Defining and calling
#include <iostream>
#include <string>
template <typename T> // `class T` means the same
T maxOf(T a, T b) { return a > b ? a : b; }
template <typename T, typename U>
auto add(T a, U b) { return a + b; } // return type deduced from the expression
template <typename T, int N> // non-type template parameter
constexpr int length(const T (&)[N]) { return N; }
int main() {
std::cout << maxOf(3, 7) << ' ' << maxOf(2.5, 1.5) << ' ' << maxOf<std::string>("pear", "apple") << '\n';
std::cout << add(1, 2.5) << '\n';
int arr[] = {1, 2, 3, 4};
std::cout << length(arr) << '\n';
// maxOf(3, 7.0); // error: T deduced as both int and double
std::cout << maxOf<double>(3, 7.5) << '\n'; // explicit template argument
}7 2.5 pear
3.5
4
7.5How instantiation works
Deduction
From the call
maxOf(3, 7)the compiler deducesT = int.Instantiation
It generates
int maxOf<int>(int, int)— a real function — and type-checks it.Reuse
Every call with
T = intin this translation unit uses the same instantiation; identical instantiations in other TUs are merged by the linker.
Overloading and explicit specialisation
#include <cstring>
#include <iostream>
template <typename T>
bool equal(const T& a, const T& b) { return a == b; }
template <> // full specialisation for const char*
bool equal<const char*>(const char* const& a, const char* const& b) { return std::strcmp(a, b) == 0; }
template <typename T>
void describe(T) { std::cout << "value\n"; }
template <typename T>
void describe(T*) { std::cout << "pointer\n"; } // overload: more specialised, preferred
int main() {
const char* x = "hi";
char buf[] = "hi";
const char* y = buf;
std::cout << equal(1, 1) << equal(x, y) << '\n'; // compares contents, not addresses
int n = 0;
describe(n);
describe(&n);
}11
value
pointerAbbreviated templates (C++20)
#include <iostream>
#include <vector>
auto sum(const auto& container) { // `auto` parameter = implicit template
typename std::decay_t<decltype(container)>::value_type total{};
for (const auto& x : container) total += x;
return total;
}
int main() {
std::cout << sum(std::vector<int>{1, 2, 3}) << ' ' << sum(std::vector<double>{0.5, 0.25}) << '\n';
}6 0.75What is template argument deduction?
Do templates cause code bloat?