Class Templates & Specialization
ক্লাস টেমপ্লেট ও স্পেশালাইজেশন
1. A Generic Stack
#include <iostream>
#include <vector>
#include <stdexcept>
template<typename T>
class Stack {
std::vector<T> data_;
public:
void push(T v) { data_.push_back(std::move(v)); }
void pop() {
if (empty()) throw std::runtime_error{"empty"};
data_.pop_back();
}
const T& top() const { return data_.back(); }
bool empty() const { return data_.empty(); }
size_t size() const { return data_.size(); }
};
int main() {
Stack<int> s;
s.push(1); s.push(2); s.push(3);
std::cout << s.top() << "\n"; // 3
s.pop();
std::cout << s.top() << "\n"; // 2
}
2. Member Function Templates
A class template can have member function templates with their own parameters:
template<typename T>
class Box {
T value_;
public:
Box(T v) : value_(std::move(v)) {}
template<typename U>
bool equals(const U& o) const { return value_ == o; }
};
// Box<int>{5}.equals(5.0) // mixes types
3. Full Specialization
Provide a custom implementation for a specific type:
template<typename T>
class Storage { /* generic */ };
template<>
class Storage<bool> { /* compact bit packed */ };
This is exactly how std::vector<bool> is implemented (controversially).
4. Partial Specialization
For a specific pattern of types:
template<typename A, typename B>
struct Pair { A a; B b; };
// Partial: when both types are the same
template<typename T>
struct Pair<T, T> { T a, b; bool sameType = true; };
5. Non-type Template Parameters
template<typename T, size_t N>
class FixedArray {
T data_[N];
public:
size_t size() const { return N; }
T& operator[](size_t i) { return data_[i]; }
};
// FixedArray<int, 100> arr;
6. Practice Problems
- Write a generic
Pair<A, B>class with two members.✨ Show Answer
template<typename A, typename B> struct Pair { A first; B second; }; - Build a Queue<T> on top of std::deque.
✨ Show Answer
template<typename T> class Queue { std::deque<T> d_; public: void enqueue(T v) { d_.push_back(std::move(v)); } T dequeue() { T v = std::move(d_.front()); d_.pop_front(); return v; } bool empty() const { return d_.empty(); } }; - Why are
std::vector<int>andstd::vector<double>different types?✨ Show Answer
Each instantiation is a separate class. They share the source template but produce distinct compiled types — incompatible by assignment.
- Specialize Stack<bool> to use bit packing (sketch).
✨ Show Answer
template<> class Stack<bool> { std::vector<uint64_t> bits_; size_t n_ = 0; // pack each bool into 1 bit }; - Write a class template with a default type argument.
✨ Show Answer
template<typename T = int> struct X { T v{}; }; X<> x; // T = int - Add a member function template that converts to another type.
✨ Show Answer
template<typename T> class Box { T v_; public: template<typename U> Box<U> convert() const { return Box<U>{static_cast<U>(v_)}; } }; - Why are most STL containers class templates?
✨ Show Answer
To work for any element type without runtime cost.
std::vector<Person>stores Persons directly, with no boxing. - Where should the implementation of class template members go?
✨ Show Answer
In the header, after the class definition. Or
inlineinside the class body. Never in a .cpp (compiler can't see them). - Define a generic Stack with maximum N (non-type param).
✨ Show Answer
template<typename T, size_t N> class FixedStack { T data_[N]; size_t n_ = 0; }; - Compile error if you instantiate a Stack with a non-comparable type — when does it fire?
✨ Show Answer
When you call a member that uses the missing operator. Templates use "duck typing" — instantiation only checks the operations actually used.
- Use template alias.
✨ Show Answer
template<typename T> using Vec = std::vector<T>; Vec<int> v; - Why do partial specializations exist?
✨ Show Answer
To customize behavior for a pattern of types (e.g. all pointer types, all containers). Used heavily by STL traits.
- Specialize for pointers.
✨ Show Answer
template<typename T> struct isPointer { static constexpr bool value = false; }; template<typename T> struct isPointer<T*> { static constexpr bool value = true; }; - Why might too many template instantiations slow compilation?
✨ Show Answer
Each instantiation is fresh code generation. A heavy templated codebase can have millions of lines after instantiation. Solutions: explicit instantiation in a single .cpp.
- Use
std::array<T, N>— what kind of params does it have?✨ Show Answer
One type parameter (T), one non-type parameter (size_t N).
- Compare class template
std::pair<A, B>with ourPair.✨ Show Answer
std::pairadds: structured binding support,operator<=>,std::make_pair, hashing... Your hand-rolled Pair lacks all of that.
Summary
Class templates make data structures generic. Each instantiation is a separate type. Specialization (full or partial) lets you customize behavior for specific types or type patterns. Non-type parameters allow sizes and other values as template arguments. Implementations live in headers.