Секрет полягає в тому, що шаблон може бути спеціалізований для деяких типів. Це означає, що він також може визначати інтерфейс абсолютно різний для декількох типів. Наприклад, ви можете написати:
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>
reference
T
reference
Тепер, що станеться, якщо ви пишете власні шаблони за допомогою цього 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
раніше, коли ви використовуєте вкладений тип шаблону у своїх шаблонах. (Звичайно, лише якщо параметр шаблону використовується для цього внутрішнього шаблону.)