Лекция 11

05.09.2025 Обновлено: 05.09.2025

Лекция 11. Шаблоны классов и функций

Шаблоны

«Способ объяснить компилятору, как мы хотим решить ту или иную шаблонную задачу.»

  • Шаблоны определяют семейство функций, классов, типов и переменных.
  • Шаблон параметризуется одним или несколькими параметрами, которые могут быть:
    • Тип (typename T / class T)
    • Константные выражения (целочисленных типов, enum’ов)
    • Указатели (на объект, функцию, член класса)
    • std::nullptr_t
    • Вещественные числа, литеральные типы (с C++20)
  • Реализуют статический полиморфизм (полиморфизм времени компиляции).
  • Не требуют дополнительных расходов по сравнению с «прямыми» реализациями (zero-overhead).

Пример:

template <class T>
const T& max(const T& a, const T& b) {
    return a > b ? a : b;
}

Сам по себе шаблон ещё не является функцией — это «рецепт» для генерации функций.

Template argument deduction (TAD)

  • Вывод аргументов шаблона из типов фактических аргументов (подбор шаблонного параметра).
  • Перед инстанциацией все параметры шаблона должны быть известны.
  • Компилятор может вывести эти параметры из аргументов, если это можно сделать однозначно.

Пример:

int main() {
    int a = 10;
    int b = 20;
    printMe<int>(max<int>(a, b));        // явное указание типа
    printMe(max(a, b));                   // компилятор выводит сам
    printMe<CRational>(max<double>(a, b)); // явное приведение/указание
}

Инстанциация

  • Генерация кода функции или класса по шаблону для конкретных параметров.
  • Без инстанциации не происходит генерации конкретного кода шаблона.
  • При использовании шаблонной функции или класса требуется полное определение, поэтому для использования в других единицах трансляции шаблоны требуется определять в заголовочных файлах.
  • Шаблон генерирует «настоящий» класс или функцию.
  • Явная и неявная инстанциация:
    • Можно явно написать тип: func<int>(a, b);
    • Компилятор сам может понять тип, если это однозначно: func(a, b);

Class Template Argument Deduction (CTAD)

  • То же самое, что TAD, но для классов (с C++17).
  • Позволяет не указывать шаблонные параметры при создании объекта:
std::pair p(1, 2.5);  // вместо std::pair<int, double> p(1, 2.5);
std::vector v{1, 2, 3};

Non-type template parameter

Параметры шаблона, не являющиеся типами:

  • Константные выражения целочисленных типов, enum’ов.
  • Указатели (на объект, функцию, член класса).
  • std::nullptr_t.
  • Вещественные числа, литеральные типы (с C++20).
template <int N>
class Array {
    int data[N];
};
Array<10> arr;

Специализация шаблонов

  • Делаем то же самое, что и обычный шаблон, но рядом с template ставим пустые <>, а возле самого объекта <тип>, а дальше — другое определение (полное).
  • Используется, если нужны какие-то специальные действия для определённых типов.
  • Есть возможность запретить какой-то метод, если сделать специализацию и не писать в ней этот метод (или вообще оставить пустое определение).

Пример полной специализации:

template <class T>
class MyClass {
    void doSomething() { /* общая реализация */ }
};

template <>
class MyClass<bool> {
    void doSomething() { /* специальная реализация для bool */ }
};