Class templates
Module 03 showed function templates. A class template is the same idea for a type: write the class once with a placeholder T, and the compiler generates a separate, fully typed class for every T you use (Stack<int>, Stack<std::string>). Nothing is boxed or type-erased, so the generated code is as fast as if you had written each version by hand. Template parameters can also be values, such as a size: std::array<int, 4> works this way.
#include <cstddef>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
template <typename T>
class Stack {
public:
void push(const T& value) { items_.push_back(value); }
T pop() {
if (items_.empty()) throw std::out_of_range("pop on empty stack");
T top = items_.back();
items_.pop_back();
return top;
}
bool empty() const { return items_.empty(); }
std::size_t size() const { return items_.size(); }
private:
std::vector<T> items_;
};
template <typename T, std::size_t N>
class RingBuffer { // keeps only the last N values
public:
void add(const T& v) { data_[next_ % N] = v; ++next_; }
std::size_t capacity() const { return N; }
T latest() const { return data_[(next_ - 1) % N]; }
private:
T data_[N]{};
std::size_t next_ = 0;
};
int main() {
Stack<std::string> words;
words.push("templates");
words.push("are");
words.push("fun");
while (!words.empty()) std::cout << words.pop() << ' ';
std::cout << '\n';
RingBuffer<int, 3> recent;
for (int i = 1; i <= 5; ++i) recent.add(i * 10);
std::cout << "capacity " << recent.capacity() << ", latest " << recent.latest() << '\n';
}fun are templates
capacity 3, latest 50N is a compile-time constant, so T data_[N] is a fixed array inside the object: no heap allocation at all.
Add const T& peek() const to Stack that throws the same exception when empty, then use it before popping.
.h and .cpp like ordinary classes. That is also why template-heavy code compiles slowly.