Лекция 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 */ }
};