Reading — step 1 of 7
Learn
Templates are how C++ does generic programming — write code once, the compiler generates specialized versions for each type used. The STL is built on templates: std::vector<int>, std::vector<std::string>, std::map<K, V> are all template instantiations.
Function templates
template <typename T>
T max_of(T a, T b) {
return (a > b) ? a : b;
}
std::cout << max_of(3, 7); // T = int → 7
std::cout << max_of(3.14, 2.71); // T = double → 3.14
std::cout << max_of<std::string>("a", "b"); // T = std::string → "b"
template <typename T> declares the type parameter. T is then used like any type. The compiler instantiates a fresh function for each unique T you call with.
typename and class are interchangeable here: template <class T> works too. Modern style prefers typename.
Multiple type parameters
template <typename A, typename B>
auto add(A a, B b) {
return a + b; // return type deduced — could be A, B, or something promoted
}
add(3, 2.5); // int + double → double
Class templates
template <typename T>
class Box {
T value;
public:
Box(T v) : value{std::move(v)} {}
T get() const { return value; }
void set(T v) { value = std::move(v); }
};
Box<int> b1{42};
Box<std::string> b2{"hello"};
When you write Box<int>, the compiler stamps out a class with T replaced by int. Two instantiations of the same template are DIFFERENT TYPES — you can't assign a Box<int> to a Box<double>.
Templates are compiled per-instantiation
Unlike Java/C# generics (one bytecode, runtime erasure) or Rust (one binary, monomorphized at link), C++ templates are compiled FRESH every time you use them with a new type. Consequences:
- Type errors only surface AT THE INSTANTIATION POINT — error messages mention deep template internals.
- Templates must be defined in HEADERS so every translation unit can instantiate them. Putting template implementations in
.cppfiles breaks links. - Code bloat is real —
std::vector<int>andstd::vector<std::string>are completely separate code in the binary.
Type traits and concepts (briefly)
C++20 added concepts — constraints on template parameters:
#include <concepts>
template <std::integral T> // T must be an integer type
T add_one(T n) { return n + 1; }
add_one(5); // OK
add_one(3.14); // compile error — double doesn't satisfy integral
Without concepts, you used static_assert(std::is_integral_v<T>) or SFINAE — far more painful. Concepts give clearer errors and clearer intent.
GCC 9.2 (the version on Judge0) doesn't fully support concepts — you'd see them in newer code (GCC 10+).
Common mistakes
- Putting template definitions in .cpp files — linker errors. Keep them in headers.
- Confusing
typenamekeyword inside templates —typename T::value_type x;tells the compiler the dependent name is a type, not a value. - Assuming all instantiations share state — they don't.
Counter<int>::countandCounter<double>::countare different statics. - Cryptic error messages — read past the template gibberish to find the actual constraint that failed (the source line of YOUR code, not the library's).
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…