Шаг 36.
Шаблоны функций (окончание)
На этом шаге мы закончим рассматривать шаблоны функций.
Перечислим основные свойства параметров шаблона.
- Имена параметров шаблона должны быть уникальными во всем определении шаблона.
- Список параметров шаблона функций не может быть пустым, так как при этом теряется возможность параметризации и
шаблон функций становится обычным определением конкретной функции.
- В списке параметров шаблона функций может быть несколько параметров. Каждый из них должен начинаться со
служебного слова class. Например, допустим такой заголовок шаблона:
template <class type1, class type2>
Соответственно, неверен заголовок:
template <class type1, type2, type3>
- Недопустимо использовать в заголовке шаблона параметры с одинаковыми именами, т.е. ошибочен
такой заголовок:
template <class t, class t, class t>
- Имя параметра шаблона (в наших примерах type1, type2 и т.д.) имеет в определяемой шаблоном функции все права имени типа,
т.е. с его помощью могут специализироваться формальные параметры, определяться тип возвращаемого функцией значения и типы любых объектов,
локализованных в теле функции. Имя параметра шаблона видно во всем определении и скрывает другие использования того же идентификатора в области,
глобальной по отношению к данному шаблону функций. Если внутри тела определяемой функции необходим доступ к внешним объектам с тем же именем,
нужно применять операцию изменения области видимости. Следующая программа иллюстрирует указанную особенность имени параметра шаблона функций:
//OOР36_1.СРР - параметр шаблона и внешняя переменная с
// тем же именем.
#include <iostream.h>
int N; // Инициализирована по умолчанию нулевым значением.
// Функция определяет максимальное из двух значений параметров.
template <class N>
N max(N x, N y)
{ N a = x;
cout << "\nСчетчик обращений N = " << ++::N;
if (a < y) a = y;
return a;
}
void main()
{
int a = 12, b = 42;
max(a,b);
float z = 66.3, f = 222.4;
max(z,f);
}
Текст этой программы можно взять
здесь.
Результат выполнения программы:
Счетчик обращений N = 1
Счетчик обращений N = 2
Итак, одно имя нельзя использовать для обозначения нескольких параметров одного шаблона, но в разных шаблонах функций
могут быть одинаковые имена у параметров шаблонов. Ситуация здесь такая же, как и у формальных параметров при определении обычных функций,
и на ней можно не останавливаться подробнее. Действительно, раз действие параметра шаблона заканчивается в конце определения шаблона,
то соответствующий идентификатор свободен для последующего использования, в том числе и в качестве имени параметра другого шаблона.
Все параметры шаблона функций должны быть обязательно использованы в спецификациях параметров определения функции.
Таким образом, будет ошибочным такой шаблон:
template <class A, class В, class C>
В func(A n, С m) {В valu; ... }
В данном неверном примере остался неиспользованным параметр шаблона с именем B. Его применений в качестве типа возвращаемого функцией
значения и для определения объекта valu в теле функции недостаточно.
Определяемая с помощью шаблона функция может иметь любое количество непараметризованных формальных параметров. Может быть не
параметризовано и возвращаемое функцией значение. Например, в следующей программе шаблон определяет семейство функций, каждая из которых
подсчитывает количество нулевых элементов одномерного массива параметризованного типа:
//OOР36_2.СРР - прототип шаблона для семейства функций.
#include <iostream.h>
template <class D>
long count0(int, D *); // Прототип шаблона.
void main ()
{
int A[] = {1, 0, 6, 0, 4, 10};
int n = sizeof (A) /sizeof A[0] ;
cout << "\ncount0(n,A) = " << count0(n,A);
float X[] = {10.0, 0.0, 3.3, 0.0, 2.1};
n = sizeof(X)/sizeof X[0];
cout << "\ncount0(n,X) = " << count0(n,X);
}
// Шаблон функций для подсчета количества нулевых элементов
// в массиве.
template <class T>
long count0(int size, T* array)
{
long k = 0;
for (int i = 0; i < size; i++)
if (int(array[i]) == 0) k++;
return k;
}
Текст этой программы можно взять
здесь.
Результат выполнения программы:
count0(n,A) = 2
count0(n,X) = 2
В шаблоне функций count0() параметр T используется только в спецификации одного формального
параметра array. Параметр size и возвращаемое функцией значение имеют явно заданные непараметризованные типы.
Как и при работе с обычными функциями, для шаблонов функций существуют определения и описания. В качестве описания шаблона
функций используется прототип шаблона:
template <список_параметров_шаблона>
В списке параметров прототипа шаблона имена параметров не обязаны совпадать с именами тех же параметров в определении шаблона. Это
и продемонстрировано в программе.
При конкретизации шаблонного определения функции необходимо, чтобы при вызове функции типы фактических параметров, соответствующие одинаково
параметризованным формальным параметрам, были одинаковыми. Для определенного выше шаблона функций с прототипом
template <class E> void swap(E,E);
недопустимо использовать такое обращение к функции:
int n = 4; double d = 4.3;
swap(n,d); // Ошибка в типах параметров.
Для правильного обращения к такой функции требуется явное приведение типа одного из параметров. Например, вызов:
swap(double(n),d); // Правильные типы параметров.
приведет к конкретизации шаблонного определения функций с параметром типа double.
При использовании шаблонов функций возможна перегрузка как шаблонов, так и функций. Могут быть шаблоны с одинаковыми именами,
но разными параметрами. Или с помощью шаблона может создаваться функция с таким же именем, что и явно определенная функция. В обоих
случаях "распознавание" конкретного вызова выполняется по сигнатуре, т.е. по типам, порядку и количеству фактических параметров.
На следующем шаге мы рассмотрим шаблоны классов.
Предыдущий шаг
Содержание
Следующий шаг