Перейти к содержимому
Теория · Шаблоны · урок 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
}

Шаблон класса

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

У Box нет конструктора, а поле открыто. Поэтому значения полей можно перечислить в фигурных скобках в порядке их объявления: Box<int> a{42};.

Шаблоны классов уже встречались в курсе: std::vector<int> — это шаблон std::vector с аргументом int.

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

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

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.

Главное

  • Шаблон класса записывает класс один раз, а Box<int> и Box<bool> — два разных типа.
  • Полная специализация template <> struct Box<bool> — отдельная версия для одного типа.
  • Специализация выбирается только для точно своего типа, без продвижений и преобразований.
  • Специализация ничего не наследует от основного шаблона: поля и методы объявляют заново.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом