CppClass Templates

Class Templates

Just as function templates let you write one function that works with many types, class templates let you write one class that works with many types. This is exactly how containers like std::vector<T> and std::map<K, V> are implemented — they are class templates, and vector<int> and vector<std::string> are just two different instantiations of the same template.
Basic syntax
A class template is declared the same way as a function template — with template <typename T> — placed directly above the class definition. Inside the class, T can be used anywhere a type would normally go: as a member's type, a parameter type, or a return type.

box.cpp

CPP
#include <iostream>

template <typename T>
class Box {
public:
    Box(T value) : value_(value) {}

    T get() const {
        return value_;
    }

    void set(T value) {
        value_ = value;
    }

private:
    T value_;
};

int main() {
    Box<int> intBox(42);
    Box<std::string> strBox("hello");

    std::cout << intBox.get() << std::endl;   // 42
    std::cout << strBox.get() << std::endl;   // hello

    intBox.set(100);
    std::cout << intBox.get() << std::endl;   // 100

    return 0;
}
Unlike function templates, class templates almost always require you to specify the type explicitly when you create an object — Box<int>, not just Box — because there are no constructor arguments in general for the compiler to deduce from. (Modern C++17 and later can sometimes deduce class template arguments from constructor calls, a feature called class template argument deduction, or CTAD, but writing the type explicitly is still the clearest and most portable style.)
A two-type example: Pair<T, U>
Class templates can take multiple type parameters, letting you build something like a simplified version of std::pair:

pair.cpp

CPP
#include <iostream>
#include <string>

template <typename T, typename U>
class Pair {
public:
    Pair(T first, U second) : first_(first), second_(second) {}

    T getFirst() const { return first_; }
    U getSecond() const { return second_; }

private:
    T first_;
    U second_;
};

int main() {
    Pair<std::string, int> score("Alice", 95);
    std::cout << score.getFirst() << " scored " << score.getSecond() << std::endl;
    return 0;
}
Defining member functions outside the class
Just like ordinary classes, you can declare member functions inside the class and define them afterward. For a class template, the template <typename T> line must be repeated above every out-of-class definition, and the class name must be qualified as Box<T> (not just Box) using the scope resolution operator.

box_outofclass.cpp

CPP
#include <iostream>

template <typename T>
class Box {
public:
    Box(T value);
    T get() const;

private:
    T value_;
};

// Definitions outside the class body repeat "template <typename T>"
// and qualify the class name as Box<T>.
template <typename T>
Box<T>::Box(T value) : value_(value) {}

template <typename T>
T Box<T>::get() const {
    return value_;
}

int main() {
    Box<double> b(3.14);
    std::cout << b.get() << std::endl;
    return 0;
}
This is exactly how the STL is built
There is no special compiler magic behind std::vector, std::map, or std::unique_ptr — they are class templates written using the same rules shown on this page (plus a lot of careful engineering for performance and correctness). Understanding class templates is the key to understanding how the whole STL fits together, and it's the same skill you'd use to write your own generic Stack<T>, LinkedList<T>, or BinaryTree<T>.
Key points
  • Class templates are declared with template <typename T> (or multiple parameters) directly above the class.

  • You must specify the type in angle brackets when creating an object: Box<int>, Pair<std::string, int>.

  • Out-of-class member function definitions repeat the template line and qualify the class name as ClassName<T>.

  • Because templates must be visible at the point of use, class templates are written entirely in header files.