Страница 40 из 48 В результате конкретизации шаблона функции 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; /* На самом деле, можно и так… */ } |