Выбрать главу

Процесс подстановки типов и значений вместо параметров называется конкретизацией шаблона. (Подробнее мы остановимся на этом в следующем разделе.)

Список параметров нашей функции min() может показаться чересчур коротким. Как было сказано в разделе 7.3, когда параметром является массив, передается указатель на его первый элемент, первая же размерность фактического аргумента-массива внутри определения функции неизвестна. Чтобы обойти эту трудность, мы объявили первый параметр min() как ссылку на массив, а второй – как его размер. Недостаток подобного подхода в том, что при использовании шаблона с массивами одного и того же типа int, но разных размеров генерируются (или конкретизируются) различные экземпляры функции min().

Имя параметра разрешено употреблять внутри объявления или определения шаблона. Параметр-тип служит спецификатором типа; его можно использовать точно так же, как спецификатор любого встроенного или пользовательского типа, например в объявлении переменных или в операциях приведения типов. Параметр-константа применяется как константное значение – там, где требуются константные выражения, например для задания размера в объявлении массива или в качестве начального значения элемента перечисления.

// size определяет размер параметра-массива и инициализирует

// переменную типа const int

template class Type, int size

Type min( const Type (r_array)[size] )

{

const int loc_size = size;

Type loc_array[loc_size];

// ...

}

Если в глобальной области видимости объявлен объект, функция или тип с тем же именем, что у параметра шаблона, то глобальное имя оказывается скрытым. В следующем примере тип переменной tmp не double, а тот, что у параметра шаблона Type:

typedef double Type;

template class Type

Type min( Type a, Type b )

{

// tmp имеет тот же тип, что параметр шаблона Type, а не заданный

// глобальным typedef

Type tm = a b ? a : b;

return tmp;

}

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

template class Type

Type min( Type a, Type b )

{

// ошибка: повторное объявление имени Type, совпадающего с именем

// параметра шаблона

typedef double Type;

Type tmp = a b ? a : b;

return tmp;

}

Имя параметра-типа шаблона можно использовать для задания типа возвращаемого значения:

// правильно: T1 представляет тип значения, возвращаемого min(),

// а T2 и T3 – параметры-типы этой функции

template class T1, class T2, class T3

T1 min( T2, T3 );

В одном списке параметров некоторое имя разрешается употреблять только один раз. Например, следующее определение будет помечено как ошибка компиляции:

// ошибка: неправильное повторное использование имени параметра Type

template class Type, class Type

Type min( Type, Type );

Однако одно и то же имя можно многократно применять внутри объявления или определения шаблона:

// правильно: повторное использование имени Type внутри шаблона

template class Type

Type min( Type, Type );

template class Type

Type max( Type, Type );

Имена параметров в объявлении и определении не обязаны совпадать. Так, все три объявления min() относятся к одному и тому же шаблону функции:

// все три объявления min() относятся к одному и тому же шаблону функции

// опережающие объявления шаблона

template class T T min( T, T );

template class U U min( U, U );

// фактическое определение шаблона

template class Type

Type min( Type a, Type b ) { /* ... */ }

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

#include vector

// правильно: Type используется неоднократно в списке параметров шаблона

template class Type

Type sum( const vectorType , Type );

Если шаблон функции имеет несколько параметров-типов, то каждому из них должно предшествовать ключевое слово class или typename:

// правильно: ключевые слова typename и class могут перемежаться

template typename T, class U

T minus( T*, U );

// ошибка: должно быть typename T, class U или

// typename T, typename U

template typename T, U

T sum( T*, U );

В списке параметров шаблона функции ключевые слова typename и class имеют одинаковый смысл и, следовательно, взаимозаменяемы. Любое из них может использоваться для объявления разных параметров-типов шаблона в одном и том же списке (как было продемонстрировано на примере шаблона функции minus()). Для обозначения параметра-типа более естественно, на первый взгляд, употреблять ключевое слово typename, а не class, ведь оно ясно указывает, что за ним следует имя типа. Однако это слово было добавлено в язык лишь недавно, как часть стандарта C++, поэтому в старых программах вы скорее всего встретите слово class. (Не говоря уже о том, что class короче, чем typename, а человек по природе своей ленив.)