# Глава 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. Здесь можно задавать вопросы и общаться.
Задонатить. Если вам нравится курс, вы можете поддержать развитие площадки!