Функции. Основные принципы структурной методологии. Принцип формальности. Принцип иерархического упорядочивания, страница 18

Увидев ключевое слово template и следующее за ним определение функции компилятор запоминает шаблон для будущего использования и генерации кода не происходит до тех пор, пока функция не будет реально вызвана в ходе выполнения программы. Компилятор в этом случае генерирует код функции для типа, указанного при ее вызове, подставляя его  везде вместо идентификатора типа в шаблоне. Это называется реализацией шаблона функции. Каждый реализованный шаблон функции называется шаблонной функцией.

Определим шаблон семейства функций, вычисляющих абсолютное значение числовых величин разных типов:

template <class T> T abs(T n) {return n<0 ? -n : n;}

Если имеем вызов функции   abs(-10.3), то аргумент -10.3 воспринимается как имеющий тип double, и компилятор формирует определение

double abs(double n) {return n <0 ? -n : n;}

и выполняться будет именно эта функция.

При вызове функций с аргументами других типов, компилятор сгенерирует другое определение функции abs():

#include <iostream.h>

//-------------------------------------------------------------template <class T>             //шаблон семейства функций T abs(T n)

T abs(T n)

{

return (n < 0) ? -n : n;

}

//-------------------------------------------------------------int main()

{

int i1 = 5;     //инииализация переменных разных типов и знаков

int i2 = -6;

long l1 = 70000L;

long l2 = -80000L;

double d1 = 9.95;

double d2 = -10.15;

//вызовы функций

cout << "\nabs(" << i1 << ")=" << abs(i1);  //abs(int)

cout << "\nabs(" << i2 << ")=" << abs(i2);  //abs(int)

cout << "\nabs(" << l1 << ")=" << abs(l1);  //abs(long)

cout << "\nabs(" << l2 << ")=" << abs(l2);  //abs(long)

cout << "\nabs(" << d1 << ")=" << abs(d1);  //abs(double)

cout << "\nabs(" << d2 << ")=" << abs(d2);  //abs(double)

cout << endl;

return 0;

}

Результаты работы программы:

abs(5)=5

abs(-6)=6

abs(70000)=70000

abs(-80000)=80000

abs(9.95)=9.95

abs(-10.15)=10.15

Определим шаблон семейства функций для обмена значений двух передаваемых им параметров:

template <class T> void swap(T* x, T* y) {T z=*x; *x=*y; *y=z;}

При определении переменных long k=4, d=8;  и  вызове swap(&k, &d);

будет сформировано определение

void swap(long* x, long* y) {long z=*x; *x=*y; *y=z;}

При определении переменных double a=2.44,  b=66.3;   и  вызове swap(&a, &b);

будет сформировано определение

void swap(double* x, double* y) {double z=*x; *x=*y; *y=z;}

Определим шаблон семейства функций для поиска минимального из трех значений, причем функция возвращает  элемент с минимальным значением:

#include <iostream.h>

template <class T> T  min3(T x, T y, T z)

{T  min =x;

if (y<min) min = y;

if (z<min) min = z;

return  min;

}

int main()

{int a=2, b=5, c=-5;

cout << min3(a*c, b, c) << endl;                  //-10

cout << min3(0.03*a, 10.0, 5.0) << endl;     //0.06

return 0;

}

Если все 3 аргумента будут одного типа, компилятор создаст нужную функцию, если нет – то сообщение об ошибке.

Свойства параметров шаблона:

1.  имена параметров шаблона имеют в определяемой шаблоном функции все права имени типа, т.е. с их помощью могут специализироваться параметры формата, определяться тип возвращаемого функцией значения, типы любых объектов, локализованных в теле функции;

2.  в списке параметров шаблона может быть несколько параметров, но каждый должен начинаться со служебного слова class:

template <class type1, class type2, …>;

3.  имена параметров шаблона уникальны во всем определении шаблона;

4.  недопустимо использование в заголовке шаблона параметров с одинаковыми именами: