Lesson 9 · 9 of 20
Function templates · C++
Write one C++ function for many types with templates: the largest of a list of numbers, words or versions, plus a generic clamp.

A function template is a mould: template <typename T> says T is a type to be decided when the function is used. largest finds the biggest element of a std::vector<T> without knowing whether it holds integers, strings or anything else.
When you call largest(std::vector<int>{12, 47, 33}), the compiler deduces that T is int and generates a version for integers. With the std::string vector it generates another one, which compares alphabetically: "zucchini" comes last. Each type gets its own function, at no run-time cost.
All largest asks of T is that it can be compared with <. Version defines operator< (major number first, then minor on a tie), so the template works with it too and finds 2.0. If a type does not provide what the template needs, the error shows up at compile time.
clampTo keeps a value between a minimum and a maximum: a volume of 130 stays at 100 and heating at 3.5 degrees goes up to 5. All three parameters share the same T, which is why clampTo(7, 0.5, 6.5) does not compile: T cannot be int and double at once. clampTo<double>(...) states the type explicitly, and 7 becomes 7.0.
Code · main.cpp
#include <iostream>#include <string>#include <vector>// One template, many types: the compiler deduces T from the arguments.template <typename T>T largest(const std::vector<T>& items) { T best = items[0]; for (const T& x : items) if (best < x) best = x; // the only thing T needs: operator< return best;}template <typename T>T clampTo(T value, T low, T high) { return value < low ? low : (high < value ? high : value); }// Any type with operator< works, including our own.struct Version { int major, minor; bool operator<(const Version& o) const { return major != o.major ? major < o.major : minor < o.minor; }};int main() { std::cout << "Highest score: " << largest(std::vector<int>{12, 47, 33}) << "\n"; std::cout << "Last word: " << largest(std::vector<std::string>{"pear", "apple", "zucchini"}) << "\n"; Version v = largest(std::vector<Version>{{1, 4}, {2, 0}, {1, 12}}); std::cout << "Latest version: " << v.major << "." << v.minor << "\n"; std::cout << "Volume: " << clampTo(130, 0, 100) << "\n"; std::cout << "Heating: " << clampTo(3.5, 5.0, 30.0) << "\n"; // clampTo(7, 0.5, 6.5) fails: T cannot be int and double. Say it explicitly: std::cout << "Explicit T: " << clampTo<double>(7, 0.5, 6.5) << "\n";}Output · c++ -std=c++17 main.cpp -o main && ./main
Highest score: 47 Last word: zucchini Latest version: 2.0 Volume: 100 Heating: 5 Explicit T: 6.5
Key points
template <typename T>in front of a function makes it a template.- The compiler deduces
Tfrom the arguments and generates one version per type. - A template works with any type that supports the operations it uses.
function<Type>(...)sets the type by hand when deduction is not enough.- Templates are written in full, body included, before use (usually in a header).
Exercise
Write a template countAbove(const std::vector<T>& items, T limit) that counts how many elements are greater than limit, and try it with marks (int) and temperatures (double).