Секрет полягає в тому, що шаблон може бути спеціалізований для деяких типів. Це означає, що він також може визначати інтерфейс абсолютно різний для декількох типів. Наприклад, ви можете написати:
template<typename T>
struct test {
typedef T* ptr;
};
template<> // complete specialization
struct test<int> { // for the case T is int
T* ptr;
};
Можна запитати, чому це корисно і справді: це справді виглядає марним. Але брати до уваги , що, наприклад , тип має зовсім інший вигляд , ніж для інших с. Справді, це не змінює тип від типу до чогось іншого, але все-таки це може статися.std::vector<bool>referenceTreference
Тепер, що станеться, якщо ви пишете власні шаблони за допомогою цього testшаблону. Щось на зразок цього
template<typename T>
void print(T& x) {
test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
вам здається, що це нормально, тому що ви очікуєте, що test<T>::ptrце тип. Але компілятор не знає, і у справі його навіть стандарт рекомендує очікувати навпаки, test<T>::ptrне типу. Щоб сказати компілятору, що, на вашу думку, потрібно додати typenameпопередньо. Правильний шаблон виглядає приблизно так
template<typename T>
void print(T& x) {
typename test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
Підсумок: Ви повинні додавати typenameраніше, коли ви використовуєте вкладений тип шаблону у своїх шаблонах. (Звичайно, лише якщо параметр шаблону використовується для цього внутрішнього шаблону.)