Шаблоны функций
Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 64 из 104.
Представьте, что вы пишете function, чтобы find maximum двух integers, а затем понимаете, что вам нужна та же логика для double и снова для строк. Без шаблонов вам пришлось бы писать почти одинаковые function для каждого типа. Шаблоны function решают эту проблему, позволяя написать логику один раз и автоматически поручить компилятору сгенерировать версии для конкретных типов.
Шаблон функции использует ключевое слово template, за которым следуют параметры шаблона в угловых скобках:
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
int main() {
std::cout << maximum(5, 3) << std::endl; // Использует версию int
std::cout << maximum(3.14, 2.71) << std::endl; // Использует версию double
std::cout << maximum('a', 'z') << std::endl; // Использует версию char
}Компилятор анализирует каждый вызов и создаёт конкретную function для этого типа. Этот процесс называется инстанцированием шаблона. При необходимости вы также можете явно указать тип:
std::cout << maximum<double>(5, 3.14) << std::endl; // Принудительно использует версию doubleШаблоны могут иметь несколько параметров типа, что позволяет создавать ещё более гибкие конструкции:
template <typename T, typename U>
void printPair(T first, U second) {
std::cout << first << ", " << second << std::endl;
}
printPair(42, "hello"); // T=int, U=const char*
printPair(3.14, 100); // T=double, U=intШаблоны функций обеспечивают полиморфизм на этапе компиляции — тип определяется при компиляции кода, а не во время выполнения. Это означает отсутствие накладных расходов во время выполнения по сравнению с виртуальными функциями, что делает шаблоны идеальными для обобщённого кода, критичного к производительности.
Задание
ЛегкоДавайте создадим набор утилит с использованием шаблонов function для создания повторно используемых операций, работающих с любым совместимым типом. Вы организуете свои обобщённые функции в заголовочном файле и продемонстрируете их гибкость в своей программе main.
Вы создадите два файла:
MathUtils.h: Define набор шаблонов function, выполняющих распространённые операции:minimum: шаблонная function, которая принимает два значения одного и того же типа и возвращает меньшее из них.clamp: шаблонная function, которая принимает три параметра: значение, нижнюю границу и верхнюю границу. Она возвращает значение, ограниченное заданными границами (возвращает low, если value меньше low, high, если value больше high, в противном случае возвращает само value).swapValues: шаблонная function, которая принимает две ссылки одного и того же типа и exchanges их значения.main.cpp: Read шесть входных значений (каждое в отдельной строке):- Первое integer
- Второе integer
- Значение double для ограничения
- Нижняя граница (double)
- Верхняя граница (double)
- A character
Продемонстрируйте свои шаблоны, выполнив следующие действия:
- Найдите minimum двух integer и выведите:
Min of <a> and <b>: <result> - Найдите minimum characters
'm'и вашего входного character и выведите:Min of m and <char>: <result> - Ограничьте значение double и выведите:
Clamp <value> to [<low>, <high>]: <result> - Ограничьте первый integer диапазоном [0, 100] и выведите:
Clamp <value> to [0, 100]: <result> - Поменяйте местами два integer и выведите:
After swapValues: <a>, <b>
Например, при входных значениях 25, 10, 3.7, 1.0, 5.0 и z:
Min of 25 and 10: 10
Min of m and z: m
Clamp 3.7 to [1, 5]: 3.7
Clamp 25 to [0, 100]: 25
After swapValues: 10, 25Обратите внимание, как каждая шаблонная function без проблем работает с integer, double и character: компилятор создаёт подходящую версию для каждого используемого вами типа. Ваша function swapValues должна изменять исходные переменные через ссылки, демонстрируя, что шаблоны работают с параметрами-ссылками так же, как обычные функции.
Попробуйте сами
#include <iostream>
#include "MathUtils.h"
using namespace std;
int main() {
// Считать входные данные
int a, b;
double value, low, high;
char ch;
cin >> a;
cin >> b;
cin >> value;
cin >> low;
cin >> high;
cin >> ch;
// TODO: Используйте шаблон minimum, чтобы найти минимум двух целых чисел
// Вывести: "Min of <a> and <b>: <result>"
// TODO: Используйте шаблон minimum, чтобы найти минимум 'm' и входного символа
// Вывести: "Min of m and <char>: <result>"
// TODO: Используйте шаблон clamp для значения double
// Вывести: "Clamp <value> to [<low>, <high>]: <result>"
// TODO: Используйте шаблон clamp для первого целого числа с диапазоном [0, 100]
// Вывести: "Clamp <value> to [0, 100]: <result>"
// TODO: Используйте шаблон swapValues для двух целых чисел
// Print: "After swapValues: <a>, <b>"
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыСборка и компиляция C++Заголовочные файлы и файлы исходного кодаПространства имен и область видимостиВведение в ООП на C++Классы и объектыУказатель 'this'Методы (функции-члены)Атрибуты (члены данных)Основы конструкторов и деструкторовИтоги — Простой калькулятор4Свойства классов
Члены экземпляра против статическихГеттеры и сеттерыКонстантные функции-членыКлючевое слово mutableСтатические методы и переменныеДружественные функции и классыИтоги — Менеджер банковских счетов7Наследование
Основы наследованияУровни доступа при наследованииПорядок вызова конструкторов и деструкторовПереопределение методовВиртуальные функции и VTableМножественное наследованиеВиртуальное наследованиеИтоги — Иерархия сотрудников10Обзор STL
Обзор и философия STLКонтейнеры STLИтераторыАлгоритмы STLФункторы и лямбда-выраженияИтоги: частота слов13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonFactory и Abstract FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy2Управление памятью
Стек и кучаУказатели и ссылкиДинамическая память (new/delete)Умные указатели в C++RAII в C++Итоги — Менеджер динамического массива5Инкапсуляция
Спецификаторы доступа в C++Спецификаторы доступа: подробный разборСокрытие данныхStruct против ClassВложенные и внутренние классыИтоги — Система учета студентов8Полиморфизм
Полиморфизм компиляции и времени выполненияПерегрузка функцийВиртуальные функции: повторениеЧистые виртуальные функцииАбстрактные классыПроектирование интерфейсов на C++Dynamic Casting и RTTIИтоги: Калькулятор фигур11Продвинутые концепции ООП
Композиция против наследованияМиксины через CRTPИдиома PimplСтирание типовEnum Classes и строгая типизацияОбработка исключений в ООППользовательские иерархии исключений14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикRAII как паттерн3Конструкторы и деструкторы
Конструктор по умолчаниюПараметризованный конструкторКонструктор копированияКонструктор перемещенияСписки инициализации конструктораДелегирующие конструкторыГлубокое погружение в деструкторыПравило трех / пяти / нуляПовторение — класс String6Перегрузка операторов
Введение в перегрузку операторовПерегрузка арифметических операторовПерегрузка операторов сравненияОператоры потоковПерегрузка оператора присваиванияПерегрузка операторов [] и ()Операторы преобразования типовИтоги — класс Matrix9Шаблоны
Шаблоны функцийШаблоны классовСпециализация шаблоновВариативные шаблоныОсновы SFINAE и Type TraitsИтоги — Обобщенный контейнерПотренируйтесь самостоятельно: Онлайн-компилятор C++