Lesson 16 / 25
Function and Class Templates
Write generic functions and classes with templates and understand instantiation.
Code that works for many types
Templates let you write a function or class once for many types, with full static type checking. A function template such as template <typename T> T max_of(T a, T b) is a blueprint; when you call it with int or double, the compiler instantiates a specialised version for that type, so there is no run-time cost. The compiler usually deduces template arguments from the call; you can also specify them explicitly (max_of<double>(3, 4.5)). Class templates (template <typename T> class Stack) work the same way, and since C++17 class template argument deduction lets you write std::vector v{1, 2, 3};. Templates can also take non-type parameters, such as std::array<int, 5>. Because the compiler needs the full template definition to instantiate it, templates are normally defined in headers. The STL is built entirely on templates. Classic downsides are long compile times and famously long error messages, which concepts (next topic) greatly improve.
One template, many instantiations
The compiler stamps out a concrete version of a template for each type it is used with.
A function template and a class template
The compiler generates code for each type actually used.
#include <stdexcept>
#include <string>
#include <vector>
template <typename T>
const T& max_of(const T& a, const T& b) {
return (a < b) ? b : a;
}
template <typename T>
class Stack {
public:
void push(T value) { items_.push_back(std::move(value)); }
T pop() {
if (items_.empty()) throw std::out_of_range("pop from empty stack");
T top = std::move(items_.back());
items_.pop_back();
return top;
}
[[nodiscard]] bool empty() const { return items_.empty(); }
private:
std::vector<T> items_;
};
int main() {
int a = max_of(3, 7); // instantiates max_of<int>
std::string s = max_of(std::string{"pear"}, std::string{"apple"}); // max_of<std::string>
Stack<std::string> undo;
undo.push("typed hello");
auto last = undo.pop();
}Templates live in headers
Putting a template's definition in a .cpp file and only its declaration in a header leads to "undefined reference" link errors, because other files cannot instantiate it. Define templates in headers (or use explicit instantiation for a known set of types).
Quick check: When does the compiler generate code for a function template?
- When the template is declared
- At run time
- When it is used with specific types (instantiation)
- Only in debug builds
Answer
When it is used with specific types (instantiation) — Templates are instantiated for each set of template arguments actually used.