Шаблоны функций в С++
Шаблоны функций, своими словами,— это инструкции, согласно которым создаются локальные версии шаблонированной функции для определенного набора параметров и типов данных.
На самом деле, шаблоны функций -это мощный инструмент в С++, который намного упрощает труд программиста. Например, нам нужно запрограммировать функцию, которая выводила бы на экран элементы массива. Задача не сложная! Но, чтобы написать такую функцию, мы должны знать тип данных массива, который будем выводить на экран. И тут нам говорят — тип данных не один, мы хотим, чтобы функция выводила массивы типа int , double , float и char .
Как оказалось, задача усложнилась. И теперь мы понимаем, что нам нужно запрограммировать целых 4 функции, которые выполняют одни и те же действия, но для различных типов данных. Так как мы еще не знакомы с шаблонами функций, мы поступим так: воспользуемся перегрузкой функций.
Таким образом, мы имеем 4 перегруженные функции, для разных типов данных. Как видите, они отличаются только заголовком функции, тело у них абсолютно одинаковое. Я написал один раз тело функции для типа int и три раза его скопировал для других типов данных.
И, если запустить программу с этими функциями, то она будет исправно работать. Компилятор сам будет определять какую функцию использовать при вызове.
Как видите, кода получилось достаточно много, как для такой простой операции. А что если, нам понадобится запрограммировать алгоритм сортировки в виде функции. Получается, что для каждого типа данных придется свою функцию создавать. То есть, сами понимаете, что один и тот же код будет в нескольких экземплярах, нам это ни к чему. Поэтому в С++ придуман такой механизм — шаблоны функций.
Мы создаем один шаблон, в котором описываем все типы данных. Таким образом исходник не будет захламляться никому ненужными строками кода. Ниже рассмотрим пример программы с шаблоном функции. Итак, вспомним условие: «запрограммировать функцию, которая выводила бы на экран элементы массива».
Заметьте, код уменьшился в 4 раза, так как в программе объявлен всего один экземпляр функции — шаблон. В main я объявил несколько массивов — четыре, для типов данных: int , double , float , char . После чего, в строках 26, 28, 30, 32, выполняется вызов функции printArray для разных массивов. Результат работы программы показан ниже.
Как видите программа корректно работает, и для этого нам понадобилось всего один раз определить функцию printArray в привычном для нас виде. Обратите внимание, что перед объявлением самой функции, в строке 5, стоит следующая запись template<typenameT> . Как раз эта запись и говорит о том, что функция printArray на самом деле является шаблоном функции, так как в первом параметре printArray стоит тип данных const T* , точно такой же как и в строке 5.
Все шаблоны функций начинаются со слова template , после которого идут угловые скобки, в которых перечисляется список параметров. Каждому параметру должно предшествовать зарезервированное слово class или typename .
Ключевое слово typename говорит о том, что в шаблоне будет использоваться встроенный тип данных, такой как: int , double , float , char и т. д. А ключевое слово class сообщает компилятору, что в шаблоне функции в качестве параметра будут использоваться пользовательские типы данных, то есть классы.
У нас в шаблоне функции использовались встроенные типы данных, поэтому в строке 5 мы написали template<typenameT> . Вместо T можно подставить любое другое имя, какое только придумаете. Давайте подробно рассмотри фрагмент кода из верхней программы, я его вынесу отдельно.
В строке 2 выполняется определение шаблона с одним параметром — T , причем этот параметр будет иметь один из встроенных типов данных, так как указано ключевое слово typename .
Ниже, в строках 3 — 8 объявлена функция, которая соответствует всем критериям объявления обычной функции, есть заголовок, есть тело функции, в заголовке есть имя и параметры функции, все как обычно. Но что эту функции превращает в шаблон функции, так это параметр с типом данных T , это единственная связь с шаблоном, объявленным ранее. Если бы мы написали
то это была бы простая функция для массива типа int .
Так вот, по сути T — это даже не тип данных, это зарезервированное место под любой встроенный тип данных. То есть когда выполняется вызов этой функции, компилятор анализирует параметр шаблонированной функции и создает экземпляр для соответственного типа данных: int , char и так далее.
Поэтому следует понимать, что даже если объем кода меньше, то это не значит, что памяти программа будет потреблять меньше. Компилятор сам создает локальные копии функции-шаблона и соответственно памяти потребляется столько, как если бы вы сами написали все экземпляры функции, как в случае с перегрузкой.
Надеюсь основную мысль по шаблонам функций до вас довел. Для закрепления материала, давайте рассмотрим еще один пример программы, с использованием шаблона функции.
Реализация шаблона класса Массив (двумерный)
Нужен шаблон класс Array, являющийся аналогом двумерных массивов. Делать решил на основе одномерных. Убил полдня, но так и не смог. Основная проблема с перегрузкой оператора индексирования. Пробовал с помощью одномерных Array<array<int>>, тоже не удалось. Возможно я тупой. Подскажите пожалуйста, что изменить в имеющемся коде, либо свою идею (фрагмент кода, если не затруднит).
Ошибки при компиляции:
2.cpp:22:52: ошибка: ‘const T& Array<T>::operator[](int, int) const’ должен иметь ровно один аргумент
Все! Теперь у нас настоящий массив. По крайней мере нечто, что выглядит как настоящий массив 🙂
C++. Примеры реализации шаблонных функций и перегруженных шаблонных функций. Обработка одиночных элементов. Обработка массивов
Примеры реализации шаблонных функций и перегруженных шаблонных функций. Обработка одиночных элементов. Обработка массивов
В данной теме продемонстрированы применение механизма шаблонов C++ для реализации перегруженных шаблонных функций. Приведены решения несколько известных задач. По данным примерам можно научиться разрабатывать собственные шаблонные функции, которые обрабатывают как одиночные элементы, так и массивы элементов.
Содержание
- 1. Примеры реализаций шаблонных функций
- 1.1. Пример шаблонной функции поиска максимума между двумя элементами
Поиск на других ресурсах:
1. Примеры реализаций шаблонных функций
1.1. Пример шаблонной функции поиска максимума между двумя элементами
В примере реализован шаблон функции Max() (шаблонной функции) для обобщенного типа T , которая определяет максимальное значение между двумя параметрами a и b .
Результат работы программы:
⇑
1.2. Пример шаблонной функции вычисления среднего арифметического значений элементов массива
В примере разработана шаблонная функция Average() для поиска среднего арифметического значений двумерного массива.
Поскольку функция Average() вычисляет среднее арифметическое значений элементов массива, то этот массив должен передаваться в функцию. Также в функцию передается размер массива.
Текст приложения, созданного по шаблону Console Application следующий.
Результат работы программы
⇑
1.3. Пример реализации шаблонных функций копирования массива и вывода массива на экран
Задача. Написать шаблон функции CopyArray() , копирующей элементы одномерного массива A[] в массив B[] . Размеры массивов считать одинаковыми. Вывод результирующего массива реализовать в шаблонной функции Print() .
Текст программного решения следующий.
Результат работы программы
⇑
2. Примеры реализаций перегруженных шаблонных функций
2.1. Пример перегрузки шаблонной функции поиска максимума между 2, 3, 4 параметрами
В примере реализована перегрузка шаблонной функции Max() , находящей максимальное значение между получаемыми параметрами. Функция реализована для двух, трех и 4 параметров.
Шаблоны
Шаблоны позволяют определить конструкции (функции, классы), которые используют определенные типы, но на момент написания кода точно не известно, что это будут за типы. Иными словами, шаблоны позволяют определить универсальные конструкции, которые не зависят от определенного типа.
Шаблон класса (class template) позволяет задать тип для объектов, используемых в классе. Но прежде чем перейти к определению шаблона класса, рассмотрим проблему, с которой мы можем столкнуться и которую позволяют решить шаблоны.
Допустим, нам надо описать класс банковского счета. Банковский счет должен иметь номер, однако на момент написания класса может быть неизвестно, какой тип будет представлять номер счета — это может быть числовой номер 1233545, а может и быть просто набор символов в виде строки, например, «1234878rtyio». На первый взгляд, мы можем просто определить два класса:
Хотя данный пример работает, но по сути мы получаем два идентичных класса, которые отличаются только типом id. Шаблоны класса позволяют уменьшить повторяемость кода, задав для класса универсальный тип. Изменим код, применив шаблоны:
Для применения шаблонов перед классом указывается ключевое слово template , после которого идут угловые скобки. В угловых скобках после слова typename идет параметр шаблона. Можно определить несколько параметров шаблона, в примере выше применяется только один параметр.
Параметр шаблона представляет произвольный идентификатор, в качестве которого, как правило, применяюся заглавные буквы, например, T. Но это необязательно. То есть в данном случае параметр T будет представлять некоторый тип, который становится известным во время компиляции. Это может быть и тип int, и double, и string, и любой другой тип. И теперь идентификатор счета будет представлять тип, который передается через параметр T.
Используем этот класс:
При использовании шаблона класса необходимо в угловых скобках после названия класса указать конкретный тип, который будет применяться вместо параметра T. Так, в первом случае вместо T применяется тип string , поэтому в конструктор класса можно передать строку:
Во втором случае применяется тип int, поэтому в конструктор передается число:
Также можно применять сразу несколько параметров. Например, необходимо определить класс банковского перевода:
Класс Transaction использует два параметра типа T и V. Параметр T определяет тип для счетов, которые участвуют вв процессе перевода. Здесь в качестве номеров счетов можно использовать и числовые и строковые значения и значения других типов. А параметр V задает тип для кода операции — опять же это может быть любой тип.
При использовании шаблона в этом случае надо указать два типа:
Типы передаются параметрам по позиции. Так, тип string будет использоваться вместо параметра T, а тип int — вместо параметра V.