C++. Бархатный путь. Часть 2 - Шаблоны функций и шаблонные функции. Часть 2
ОГЛАВЛЕНИЕ
В результате конкретизации шаблона функции min() транслятор строится следующий вариант программы с двумя шаблонными функциями. По выражению вызова на основе шаблона строится шаблонная функция. Почувствуйте прелесть употребления однокоренных слов! Шаблон функции и шаблонная функция - два разных понятия.
int min (int a, int b);
float min (float a, float b);
int main (void)
{
min(10,20);
min(10.0,20.0);
return 1;
}
int min (int a, int b)
{
return a < b ? a : b;
}
float min (float a, float b)
{
return a < b ? a : b;
}
Построение шаблонной функции осуществляется на основе выражений вызова. При этом в качестве значений параметров в выражении вызова могут быть использованы значения любых типов, для которых определены используемые в теле функции операции. Так, для функции min() тип параметров зависит от области определения операции сравнения <.
Типы формального параметра шаблона и значения параметра выражения вызова сопоставляются без учёта каких-либо модификаторов типа. Например, если параметр шаблона в определении функции объявлен как
template <class Type>
Type min (Type *a, Type *b)
{
return a < b ? a : b;
}
и при этом вызов функции имеет вид:
int a = 10, b = 20;
int *pa = &a, *pb = &b;
min(pa,pb);
то в процессе конкретизации идентификатор типа Type будет замещён именем производного типа int:
int min (int *a, int *b)
{
return a < b ? a : b;
}
В процессе конкретизации недопустимы расширения типов и другие преобразования типов параметров:
template <class Type>
Type min (Type a, Type b)
{
return a < b ? a : b;
}
unsigned int a = 10;
:::::
min(1024,a);
/*
Здесь транслятор сообщит об ошибке. В вызове функции тип второго
фактического параметра модифицирован по сравнению с типом первого
параметра - int и unsigned int. Это недопустимо. В процессе
построения новой функции транслятор не распознаёт модификации типов.
В вызове функции типы параметров должны совпадать. Исправить ошибку
можно с помощью явного приведения первого параметра.
*/
min((unsigned int)1024,a);
:::::
Имя параметра шаблона в определяемой функции используется в качестве имени типа. С его помощью специализируются формальные параметры, определяется тип возвращаемого значения, определяется тип объектов, локализованных в теле функции. Имя параметра шаблона скрывает объекты с аналогичным именем в глобальной по отношению к определению шаблонной функции области видимости. Если в теле шаблонной функции необходим доступ к внешним объектам с тем же именем, следует использовать операцию изменения области видимости.
И опять пример с излюбленным классом ComplexType. На множестве комплексных чисел определены лишь два отношения: равенства (предполагает одновременное равенство действительной и мнимой частей) и неравенства (предполагает все остальные случаи). В нашей новой программе мы объявим и определим шаблон функции neq(), которая будет проверять на неравенство значения различных типов.
Для того, чтобы построить шаблонную функцию neq() для комплексных чисел, нам придётся дополнительно определить операторную функцию-имитатор операции != для объектов-представителей множества комплексных чисел. Это важно, поскольку операция != явным образом задействована в шаблоне neq(). Транслятор не поймёт, как трактовать символ != , а, значит, и как строить шаблонную функцию neq(ComplexType, ComplexType), если эта операторная функция не будет определена для класса ComplexType.
#include <iostream.h>
template <class Type>
int neq (Type, Type); /*Прототип шаблона функции.*/
class ComplexType
{
public:
double real;
double imag;
// Конструктор умолчания.
ComplexType(double re = 0.0, double im = 0.0)
{real = re; imag = im;}
/*
Операторная функция != . Без неё невозможно построение шаблонной функции neq() для комплексных чисел.
*/
int operator != (ComplexType &KeyVal)
{
if (real == KeyVal.real && imag == KeyVal.imag) return 0;
else return 1;
}
};
void main ()
{
// Определены и проинициализированы переменные трёх типов.
int i = 1, j = 2;
float k = 1.0, l = 2.0;
ComplexType CTw1(1.0,1.0), CTw2(2.0,2.0);
//На основе выражений вызова транслятор строит три шаблонных функции.
cout << "neq() for int:" << neq(i,j) << endl;
cout << "neq() for float:" << neq(k,l) << endl;
cout << "neq() for ComplexType:" << neq(CTw2,CTw3) << endl;
}
/*Определение шаблона функции.*/
template <class Type>
int neq (Type a, Type b)
{
return a != b ? 1 : 0;
// return a != b; /* На самом деле, можно и так… */
}