Function Templates
2 min read
Function Templates
A function template defines a function that works with any type. The compiler generates a concrete version — a specialization — for each distinct set of types used at call sites.
Basic template
#include <iostream>
template <typename T>
T max_of(T a, T b) {
return (a > b) ? a : b;
}
int main() {
std::cout << max_of(3, 7) << "\n"; // 7 — T = int
std::cout << max_of(3.14, 2.71) << "\n"; // 3.14 — T = double
std::cout << max_of('a', 'z') << "\n"; // z — T = char
}
The compiler deduces T from the argument types. You can also specify it explicitly: max_of<double>(3, 4).
Multiple type parameters
template <typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {
return a + b;
}
std::cout << add(1, 2.5) << "\n"; // 3.5 — T=int, U=double, result=double
decltype(a + b) deduces the return type from the expression. In C++14 and later, auto return type with no trailing type achieves the same:
template <typename T, typename U>
auto add(T a, U b) {
return a + b;
}
Template with non-type parameters
template <typename T, int N>
T dot_product(const T (&a)[N], const T (&b)[N]) {
T result = 0;
for (int i = 0; i < N; i++) result += a[i] * b[i];
return result;
}
int main() {
int u[] = {1, 2, 3};
int v[] = {4, 5, 6};
std::cout << dot_product(u, v) << "\n"; // 32
}
Explicit specialization
Override the template for a specific type:
template <typename T>
std::string to_str(T x) {
return std::to_string(x);
}
template <>
std::string to_str<bool>(bool x) {
return x ? "true" : "false";
}
std::cout << to_str(42) << "\n"; // "42"
std::cout << to_str(true) << "\n"; // "true"
constexpr function templates
Template functions can be constexpr, enabling compile-time evaluation:
template <typename T>
constexpr T square(T x) { return x * x; }
static_assert(square(5) == 25); // evaluated at compile time
constexpr double d = square(1.5); // d = 2.25, known at compile time
Variadic templates
A variadic template accepts any number of type arguments:
#include <iostream>
// Base case
void print_all() {}
// Recursive case
template <typename T, typename... Rest>
void print_all(T first, Rest... rest) {
std::cout << first << " ";
print_all(rest...);
}
int main() {
print_all(1, 2.5, "hello", true); // 1 2.5 hello 1
std::cout << "\n";
}
C++17 fold expressions simplify this:
template <typename... Args>
void print_all(Args... args) {
(std::cout << ... << args); // fold over <<
}
Learn modern C++ through working code. Each chapter introduces one concept — variables, functions, classes, templates, smart pointers, concurrency — with a clear example, a line-by-line explanation, and notes on how it applies in real programs.
View book →