Если в глобальной области видимости объявлен объект, функция или тип с тем же именем, что у параметра шаблона, то глобальное имя оказывается скрытым. В следующем примере тип переменной 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, а человек по природе своей ленив.)
Ключевое слово typename упрощает разбор определений шаблонов. (Мы лишь кратко остановимся на том, зачем оно понадобилось. Желающим узнать об этом подробнее рекомендуем обратиться к книге Страуструпа “Design and Evolution of C++”.)