# Глава 5.6. Шаблоны
[Шаблоны](https://en.cppreference.com/w/cpp/language/templates) (templates) позволяют писать обобщённый код без привязки к конкретным типам и константам. Это эффективный способ переиспользования кода.
Рассмотрим функцию `max()`:
```cpp
int max(int a, int b)
{
return a < b ? b : a;
}
```
Как быть, если нужно применять её не только для `int`, но и для других типов — `double`, `char` и даже строк? Под каждый тип мы могли бы завести перегрузку. Но это приведёт к копированию одного и того же кода, отличающегося лишь типами. Мы нарушим отличный принцип «не повторяйся» [(DRY, Don’t repeat yourself).](https://ru.wikipedia.org/wiki/Don%E2%80%99t_repeat_yourself)
## Шаблоны функций
Так давайте же научим функцию `max()` работать с параметрами любого типа. Создадим шаблон:
```cpp {.example_for_playground .example_for_playground_016}
template<class T> // T - параметр шаблона
T max(T a, T b) // a и b - параметры функции
{
return a < b ? b : a;
}
```
Ключевое слово `template` в объявлении функции означает, что перед нами шаблон. После него в треугольных скобках через запятую перечисляются _параметры шаблона._ После ключевого слова `class` указывается имя параметра. Чаще всего шаблонным параметрам дают короткие имена с заглавной буквы. Например, `T` от слова `type`.
После перечисленных в треугольных скобках параметров шаблона идёт функция. В ней доступны параметры шаблона по их именам. Функция `T max(T a, T b)` принимает параметры `a` и `b` некоего заранее неизвестного типа `T`. И возвращает значение этого же типа.
А теперь убедимся, что при вызове функция умеет принимать аргументы самых разных типов!
```cpp {.example_for_playground .example_for_playground_017}
max(5, 6); // 6
max('z', 'a'); // z
max(1.01, 1.02); // 1.02
```
## Инстанцирование шаблонов
Как это работает? В процессе сборки программы компилятор находит все вызовы шаблонных функций. Для каждого уникального набора аргументов он _инстанцирует_ шаблон: порождает обычную функцию из шаблона функции. Практически это означает, что компилятор вместо программиста многократно копирует одну и ту же функцию, меняя лишь типы. В нашем примере это компилятор создал три _специализации шаблона:_
```cpp
int max(int a, int b) { return a < b ? b : a; }
char max(char a, char b) {return a < b ? b : a; }
double max(double a, double b) { return a < b ? b : a; }
```
Порой без подсказки компилятор не может самостоятельно вывести все типы, чтобы инстанцировать шаблон. Тогда их требуется явно указать _при вызове_ функции. В случае с `max()` это избыточно: компилятор сам определяет тип `T`, ведь это тип переданных в функцию аргументов. Тем не менее, мы можем задать аргумент шаблона явно, передав его в треугольных скобках:
```cpp {.example_for_playground .example_for_playground_018}
max<int>(5, 6);
max<char>('z', 'a');
max<double>(1.01, 1.02);
```
Напишите шаблонную функцию `str_none_of()`. Функция должна принимать строку и предикат. Предикат — это функция, возвращающая `true` либо `false`. Функция `str_none_of()` должна вернуть `true`, если предикат не выполняется ни над одним символом строки. {.task_text #block-predicate}
Тип предиката — это и есть параметр шаблона. {.task_text}
Например, у нас есть строка `std::string s="generic"` и предикат `bool is_a(char c) {return c == 'a'; }`. Вызов `str_none_of(s, is_a)` должен вернуть `true`. {.task_text}
```cpp {.task_source #cpp_chapter_0056_task_0090}
```
У шаблона должен быть единственный параметр, например `class Fn`. Тогда функция будет выглядеть так: `bool str_none_of(std::string s, Fn pred)`. В ней в цикле по каждому символу `c` строки `s` нужно применить предикат: `pred(c)`. Если он хотя бы раз вернул `true`, функция возвращает `false`. {.task_hint}
```cpp {.task_answer}
template<class Fn>
bool str_none_of(std::string s, Fn pred)
{
for (char c: s)
{
if (pred(c))
return false;
}
return true;
}
```
Шаблонными могут быть не только функции, но и классы. Например, все контейнеры из стандартной библиотеки — это шаблоны!
----------
## Резюме
- Шаблоны нужны для написания обобщённого кода без привязки к конкретным типам.
- Чтобы завести шаблонную функцию, используется ключевое слово `template`.
- При сборке программы компилятор порождает специализации шаблона: из шаблонной функции создает обычную на основе переданных в нее аргументов.
- Этот процесс называется инстанцированием шаблона.
Наша группа в telegram. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!