Перейти к содержимому
Теория · Шаблоны · урок 5 из 11

Шаблоны классов и специализация

Структура, которая хранит одно значение и печатает его, для int, double и bool выглядит одинаково — меняется только тип поля. Такой класс тоже записывают шаблоном, а тип указывают в угловых скобках при создании объекта:

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) устроен как шаблон функции: перед struct или class стоит template <typename T>, а T заменяет тип в полях и методах. Box<int> — обычный класс, который компилятор создаёт, подставив int вместо T. Box<int> и Box<bool> — разные типы, и объект одного нельзя присвоить переменной другого.

У Box нет конструктора, а поле открыто. Поэтому значения полей можно перечислить в фигурных скобках в порядке их объявления: Box<int> a{42};. Шаблоны классов уже встречались в курсе: std::vector<int> — это шаблон std::vector с аргументом int. С C++17 аргумент шаблона класса выводится и из аргументов конструктора: std::vector v{1, 2, 3}; создаёт std::vector<int>.

Полная специализация

Для bool основной шаблон печатает 1, а нужно true. Для одного конкретного типа шаблону можно дать отдельную версию — полную специализацию (full specialization):

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

Пустые угловые скобки в template <> значат, что параметров не осталось: тип уже задан в Box<bool>. Специализацию пишут после основного шаблона, и с ней f.print() выводит true.

Какая версия выбирается

Box<bool> можно построить и из основного шаблона с T = bool. Но для этого типа есть полная специализация, и компилятор берёт её вместо основного шаблона. Специализация подходит только для своего типа: продвижения и преобразования, как при выборе перегрузки, здесь не учитываются. Поэтому Box<int> строится из основного шаблона, хотя int и преобразуется в bool.

Частая ошибка

В специализации оставили только метод, который нужно изменить:

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

Это ошибка компилятора. Специализация — отдельный класс: из основного шаблона она не получает ни полей, ни методов. Объявите в ней всё, что нужно, в том числе поле value.