Why Do Templates Exist?
Consider this problem:
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
long add(long a, long b) { return a + b; }
Problems:
- Code duplication
- Hard to maintain
- More types → more overloads
- Still limited flexibility
What We Want:
- Write logic once
- Reuse it for any compatible type
- Pay zero runtime penalty
The Solution:
Templates
What Is a C++ Template?
A template is a compile-time code generator.
It tells the compiler:
“When you see this template used with a specific type,
generate a real function or class for that type.”
Templates are resolved at compile time — not runtime
- Template functions
- Template classes
it is where you find an angle bracket
template <typename Type> decleration
template <class Type> decleration
Function Templates
Basic Function Template
template <typename T>
T add(T a, T b) {
return a + b;
}
Usage:
add(2, 3); // T = int
add(2.5, 3.1); // T = double
What the Compiler Generates
add<int>(int, int)
add<double>(double, double)
template <typename T>
T add(T, T)
|
| Instantiation
v
int add(int, int)
double add(double, double)
Multiple Template Parameters
template <typename T, typename U>
auto multiply(T a, U b) {
return a * b;
}
Usage:
multiply(2, 3.5); // T=int, U=double
Generated type:
auto → decltype(a * b) → double
Class Templates
Basic Class Template
template <typename T>
class Box {
public:
T value;
Box(T v) : value(v) {}
};
Usage:
Box<int> b1(10);
Box<std::string> b2("Hello");
Instantiation diagram:
Box<T>
|
|--> Box<int>
|--> Box<std::string>
Member Function Templates
A class does not need to be templated for its functions to be.
class Printer {
public:
template <typename T>
void print(const T& value) {
std::cout << value << "\n";
}
};
Why?
- One utility class
- Many data types
- No duplication
Template Specialization
Full Specialization
Used when one type needs different behavior
template <typename T>
struct TypeInfo {
static const char* name() { return "Generic"; }
};
template <>
struct TypeInfo<int> {
static const char* name() { return "Integer"; }
};
Usage:
TypeInfo<double>::name(); // Generic
TypeInfo<int>::name(); // Integer
Partial Specialization (Class Templates Only)
template <typename T>
struct IsPointer {
static constexpr bool value = false;
};
template <typename T>
struct IsPointer<T*> {
static constexpr bool value = true;
};
Usage:
IsPointer<int>::value; // false
IsPointer<int*>::value; // true
Pattern matching:
T -> false
T* -> true
Variadic Templates (Parameter Packs)
Used when number of arguments is unknown at compile time.
Simple Example
template <typename... Args>
void printAll(Args... args) {
(std::cout << ... << args) << "\n";
}
Call:
printAll(1, " ", 3.14, "\n");
Expansion:
((cout << 1) << " ") << 3.14 << "\n"
Template Recursion (Old Style)
template <int N>
struct Factorial {
static constexpr int value = N * Factorial<N - 1>::value;
};
template <>
struct Factorial<0> {
static constexpr int value = 1;
};
Compile-time computation:
int x = Factorial<5>::value; // 120
This runs at compile time
Alias Templates (`using`)
Cleaner alternative to typedef
template <typename T>
using Vec = std::vector<T>;
Usage:
Vec<int> v;
Template Constraints (C++20 Concepts)
The Problem
Templates accept anything, even invalid types.
add("a", "b"); // Compiles? Errors are ugly.
The Solution: Concepts
#include <concepts>
template <typename T>
requires std::integral<T>
T add(T a, T b) {
return a + b;
}
Or cleaner:
template <std::integral T>
T add(T a, T b);
When Should You Use Templates?
| Use Case | Use Templates? |
|---|---|
| Algorithms | ✅ Yes |
| Containers | ✅ Yes |
| Compile-time config | ✅ Yes |
| Runtime polymorphism | ❌ No |
| Plugin systems | ❌ No |
| Performance-critical code | ✅ Absolutely |
Common Template Pitfalls
1. Code Bloat
Too many instantiations increase binary size.
2. Long Compile Times
Heavy template metaprogramming slows builds.
3. Error Messages
Without concepts → unreadable diagnostics.
Templates in the STL (Real-World Proof)
std::vector<int>
std::vector<double>
std::sort(begin, end)
std::map<Key, Value>
The entire STL exists because of templates.
Standard Template Library (STL)
C++ added its own library which depends on Templates and called it STL or Standard Template Library.
It is part of the ANSI/ISO C++ standard, meaning every compliant C++ compiler must provide it.
STL is not “just a library”.
It is a design philosophy built on:
- Generic programming
- Compile-time polymorphism
- Performance predictability
- Separation of data, traversal, and logic
Why STL Exists
Before STL, C++ programmers had to:
- Reimplement lists, arrays, trees
- Write custom sorting logic for each data type
- Manually manage memory and iteration
This led to:
- Code duplication
- Bugs
- Inconsistent performance
- Non-portable implementations
STL Solves This By Separating Concerns
[ Container ] ---> stores data
[ Iterator ] ---> traverses data
[ Algorithm ] ---> operates on data
Algorithms don’t care how data is stored.
Containers don’t care what algorithm runs on them.
Templates glue everything together at compile time.
STL Components Overview
The STL consists of three main components:
- Containers
- Iterators
- Algorithms
This separation is one of the most important design decisions in modern C++.