Шаблоны — обобщённое программирование
ООП решает повторное использование через наследование и интерфейсы — но только в пределах иерархии типов. Шаблоны решают другую задачу: параметризованный код, который компилятор конкретизирует под каждый нужный тип. Алгоритм пишется один раз — компилятор генерирует версии под int, std::string, любой пользовательский тип. Проверка типов — compile-time, накладных расходов в runtime нет.
C++-шаблоны — это полноценная система типов, не текстовый макрос. Компилятор проверяет корректность, выводит типы, применяет overload resolution и ADL, выбирает наиболее специфичную специализацию, и (с C++20) проверяет concept-ограничения. Кандидат на собеседовании, путающий substitution failure с hard error или считающий шаблоны «умными макросами», в лучшем случае попадает в junior+.
Карта темы
- Базовый шаблон — шаблонные функции и классы, header-only правило.
- Инстанцирование — implicit/explicit,
extern template, template bloat. - Специализация — полная и частичная; почему partial-spec нет для функций.
- Дополнительные возможности — NTTP, template-template параметры, дефолтные аргументы.
- Variadic-шаблоны —
typename...,sizeof..., рекурсивная распаковка. - Раскрытие пакета — оператор
...и fold expressions. - Вывод типов — argument deduction,
decltype,auto, CTAD. - SFINAE — substitution failure,
enable_if,void_t, immediate context. - Концепты (C++20) — именованные ограничения,
requires-выражения. - Static polymorphism / CRTP — диспетчеризация без vtable.
- constexpr-метапрограммирование —
constexpr,consteval,if constexpr,constinit. - Зависимые имена —
typename,template, two-phase lookup.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Тело шаблонной функции в .cpp | undefined reference на линковке в каждой TU, где шаблон используется |
max(3, 3.14) без явного T | Conflict deduction — компилятор не выбирает между int и double |
template<> partial specialization для функции | Ошибка компиляции — только перегрузка |
| Полная специализация после первого использования | UB |
| Базовый класс шаблона + неквалифицированное имя | greet() не находит метод базы; нужно this->greet() |
Зависимый тип без typename | Компилятор считает T::value_type значением — синтаксическая ошибка |
| SFINAE-ошибка в теле, а не в сигнатуре | Hard error — не отсекается, валит компиляцию |
Шаблонный класс, используемый в 50 TU без extern template | Многократная компиляция, медленный линкинг |
Унарный fold по + с пустым пакетом | Ошибка — используйте binary fold с identity 0 |
Использование auto там, где нужна точная ссылка | Копия вместо ссылки — теряется производительность; нужен decltype(auto) |
Значение для собеседований
Шаблоны — одна из самых частых глубоких тем на позициях middle и senior C++. Интервьюер проверяет понимание механизмов, а не знание синтаксиса.
Что конкретно проверяют:
- Template argument deduction — почему
max(3, 3.14)не компилируется, как исправить. - Инстанцирование и header-only правило; ODR и
extern templateдля контроля времени компиляции. - Разница полной и частичной специализации; почему partial-spec нет для функций.
- SFINAE — immediate context, отличие от hard error; почему концепты «лучше».
- Variadic + fold — как именно раскрывается пакет, четыре формы fold expression.
- CRTP — назначение, отличие от виртуальных функций, типичные применения.
typenameи two-phase lookup — почемуthis->method()в шаблонном классе.
Популярные вопросы:
- Напишите
is_same<T, U>с нуля (базовый шаблон + полная специализация). - Сделайте функцию только для числовых типов — через SFINAE и через концепты.
- Сколько инстанцирований породит
std::vector<std::vector<int>>и почему? - Что такое SFINAE и где «failure is not an error» не работает?
- Реализуйте
tupleилиtype_listчерез variadic-шаблоны. - Чем
if constexprотличается от обычногоifи зачем он нужен в шаблоне? - Почему нужно писать
typename T::value_type?
Типичная ошибка кандидата: считать шаблоны «умными макросами». Это не текстовая подстановка — это система типов с overload resolution, ADL и compile-time проверками. Без понимания разницы между substitution failure и hard error уровень middle не пройти.