Skip to content
Theory · Templates · lesson 5 of 11

Class templates and specialization

A struct that holds one value and prints it looks the same for int, double and bool. Only the type of the field changes. Such a class is also written as a template, and the type goes in angle brackets when an object is created:

C++
#include <iostream>

template <typename T>
struct Box {
    T value;
    void print() const { std::cout << value << '\n'; }
};

int main() {
    Box<int> a{42};
    Box<bool> f{true};
    a.print();  // 42
    f.print();  // 1
}

Class template

A class template works like a function template. template <typename T> stands before struct or class, and T replaces the type in fields and methods. Box<int> is an ordinary class that the compiler creates by substituting int for T. Box<int> and Box<bool> are different types, and an object of one cannot be assigned to a variable of the other.

Box has no constructor, and its field is public. So the values of the fields can be listed in curly braces in the order they are declared: Box<int> a{42};. Class templates have already appeared in the course: std::vector<int> is the template std::vector with the argument int. Since C++17, a class template argument is also deduced from the constructor arguments: std::vector v{1, 2, 3}; creates a std::vector<int>.

Full specialization

For bool, the primary template prints 1 where true is needed. A template can be given a separate version for one specific type, a full specialization:

C++
template <>
struct Box<bool> {
    bool value;
    void print() const { std::cout << (value ? "true" : "false") << '\n'; }
};

The empty angle brackets in template <> mean that no parameters are left: the type is already given in Box<bool>. The specialization is written after the primary template, and with it f.print() prints true.

Which version is chosen

Box<bool> could also be built from the primary template with T = bool. But this type has a full specialization, and the compiler takes it instead of the primary template. A specialization fits only its own type: promotions and conversions, as in overload resolution, play no part here. That is why Box<int> is built from the primary template, even though int converts to bool.

Common mistake

The specialization keeps only the method that needs to change:

C++
template <>
struct Box<bool> {
    void print() const { std::cout << (value ? "true" : "false") << '\n'; }  // ✗
};
TEXT
error: use of undeclared identifier 'value'

This is a compiler error. A specialization is a separate class: it gets no fields or methods from the primary template. Declare everything it needs in it, the field value included.