Class Templates
2 min read
Class Templates
A class template defines a family of classes. The standard library is built on class templates: std::vector<T>, std::map<K,V>, std::pair<T,U> are all instantiations of class templates.
Basic class template
#include <iostream>
#include <stdexcept>
template <typename T>
class Stack {
T data[256];
int top = 0;
public:
void push(const T& value) {
if (top >= 256) throw std::overflow_error("stack full");
data[top++] = value;
}
T pop() {
if (top == 0) throw std::underflow_error("stack empty");
return data[--top];
}
T& peek() { return data[top - 1]; }
bool empty() const { return top == 0; }
int size() const { return top; }
};
int main() {
Stack<int> s;
s.push(10); s.push(20); s.push(30);
std::cout << s.pop() << "\n"; // 30
std::cout << s.peek() << "\n"; // 20
Stack<std::string> words;
words.push("hello");
words.push("world");
std::cout << words.pop() << "\n"; // world
}
For class templates, the type must be specified explicitly: Stack<int>, not Stack. C++17 adds class template argument deduction (CTAD) which can infer it from constructor arguments.
Class template argument deduction (CTAD)
template <typename T>
class Box {
T value;
public:
Box(T v) : value(v) {}
T get() const { return value; }
};
Box b(42); // T deduced as int — C++17
Box s("hello"); // T deduced as const char*
Member function definitions outside the class
For large classes, method definitions are often placed outside the class body:
template <typename T>
class Queue {
std::vector<T> data;
public:
void enqueue(const T& v);
T dequeue();
};
template <typename T>
void Queue<T>::enqueue(const T& v) {
data.push_back(v);
}
template <typename T>
T Queue<T>::dequeue() {
T front = data.front();
data.erase(data.begin());
return front;
}
Template definitions must be visible at the point of instantiation, so they typically live in header files.
Partial specialization
You can specialize a class template for a subset of types:
// Primary template
template <typename T>
class Storage {
T value;
public:
Storage(T v) : value(v) {}
T get() const { return value; }
};
// Specialization for pointer types
template <typename T>
class Storage<T*> {
T* ptr;
public:
Storage(T* p) : ptr(p) {}
T get() const { return *ptr; }
};
Function templates do not support partial specialization — use overloads or class templates to work around this.
Template template parameters
A template can take another template as a parameter:
template <typename T, template <typename> class Container>
class Adapter {
Container<T> data;
public:
void add(const T& v) { data.push_back(v); }
std::size_t size() const { return data.size(); }
};
Adapter<int, std::vector> a;
a.add(1); a.add(2);
std::cout << a.size() << "\n"; // 2
Learn modern C++ through working code. Each chapter introduces one concept — variables, functions, classes, templates, smart pointers, concurrency — with a clear example, a line-by-line explanation, and notes on how it applies in real programs.
View book →