10.0 What This Teaches
- Function templates and type deduction
- Class templates
- Template parameters:
typename Tand non-type parameters - Compile-time branching with
if constexpr(C++17) - Where templates fit vs overloading
10.1 Function Templates
template<typename T>
T max_of(T a, T b) { return a > b ? a : b; }
max_of(3, 7); // T = int
max_of(2.5, 1.8); // T = double
max_of(std::string("apple"), std::string("fig")); // T = std::string
T from the argument types. You can also
specify it explicitly: max_of<double>(3, 7.0). The
template generates a separate function for each distinct type used - this
is called instantiation.
10.2 Multiple Type Parameters
template<typename T, typename U>
void print_pair(T first, U second) {
std::cout << first << ", " << second << "\n";
}
print_pair(42, 3.14);
print_pair(std::string("name"), 100);
10.3 Class Templates
template<typename T>
class Stack {
public:
void push(const T& val) { data_.push_back(val); }
void pop() { data_.pop_back(); }
const T& top() const { return data_.back(); }
bool empty() const { return data_.empty(); }
private:
std::vector<T> data_;
};
Stack<int> si;
si.push(1); si.push(2);
std::cout << si.top(); // 2
Stack<std::string> ss;
ss.push("hello");
Stack<int>. Class Template Argument Deduction (CTAD,
C++17) can infer it in some cases, but explicit is clearer.
10.4 Compile-time Branching with if constexpr
#include <type_traits>
template<typename T>
std::string type_label() {
if constexpr (std::is_integral_v<T>) return "integral";
else if constexpr (std::is_floating_point_v<T>) return "floating point";
else return "other";
}
type_label<int>(); // "integral"
type_label<double>(); // "floating point"
if constexpr evaluates the condition at compile time and only
compiles the matching branch. This lets template code behave differently for
different types without runtime overhead.
10.5 Example - All Together
// Templates - function templates, class templates, type deduction.
#include <iostream>
#include <vector>
#include <string>
#include <type_traits>
template<typename T>
T max_of(T a, T b) { return a > b ? a : b; }
template<typename T>
class Stack {
public:
void push(const T& val) { data_.push_back(val); }
void pop() { data_.pop_back(); }
const T& top() const { return data_.back(); }
bool empty() const { return data_.empty(); }
private:
std::vector<T> data_;
};
template<typename T>
std::string type_label() {
if constexpr (std::is_integral_v<T>) return "integral";
else if constexpr (std::is_floating_point_v<T>) return "floating point";
else return "other";
}
int main() {
std::cout << max_of(3, 7) << "\n"; // 7
std::cout << max_of(2.5, 1.8) << "\n"; // 2.5
Stack<int> s;
s.push(10); s.push(20); s.push(30);
while (!s.empty()) { std::cout << s.top() << " "; s.pop(); }
std::cout << "\n";
std::cout << type_label<int>() << "\n";
std::cout << type_label<double>() << "\n";
std::cout << type_label<std::string>() << "\n";
return 0;
}
7
2.5
30 20 10
integral
floating point
other
10.6 Exercise
Exercise
- Write a function template
sum(const std::vector<T>& v)that returns the sum of all elements. Test it withintanddoublevectors. - Write a class template
Pair<T, U>with public membersfirstandsecondand a constructor that takes both. Add aswap()method that swaps the values (only works when T == U). - Use
if constexprwithstd::is_same_v<T, std::string>to write a template function that prints the length of a string or the absolute value of a number.
10.7 Common Mistakes
Template definition must be in the header
.cpp file, other translation units
cannot instantiate it. Put template definitions in header (.h)
files or inline in the class body.
Type does not support the required operations
max_of(std::vector<int>{1,2}, std::vector<int>{3,4});
// error: operator> not defined for vector
Ambiguity between template and overload
template<typename T> void f(T x) {}
void f(int x) {} // ok: non-template is preferred for exact match
f(42); // calls the non-template version
10.8 Key Terms
| Term | Meaning |
|---|---|
| template<typename T> | Declares a function or class parameterized on type T |
| instantiation | Compiler generates a concrete version of the template for a specific type |
| type deduction | Compiler infers T from the argument types |
| class template | A class parameterized on one or more types |
| if constexpr | Compile-time conditional; only the matching branch is compiled |
| std::is_integral_v<T> | Compile-time boolean: true if T is an integer type |
| CTAD | Class Template Argument Deduction (C++17): infer template args from constructor args |