Дополнительно
Когда необходимо использовать ключевое слово "typename"?
рассмотрим приведенный ниже код:
template<class K>
class C {
struct P {};
vector<P> vec;
void f();
};
template<class K> void C<K>::f() {
typename vector<P>::iterator p = vec.begin();
}
Почему в данном примере необходимо ключевое слово "typename"? Существуют ли другие случаи, когда необходимо указывать "typename"?
50
3
Краткий ответ: При обращении к вложенному имени, которое является зависимым именем, т.е. вложенным внутрь экземпляра шаблона с неизвестным параметром.
Длинный ответ: В языке Си++ существует три уровня сущностей: значения, типы и шаблоны. Все они могут иметь имена, и само по себе имя не говорит о том, к какому уровню сущностей оно относится. Скорее, информация о природе сущности имени должна быть выведена из контекста.
В тех случаях, когда такой вывод невозможен, его приходится уточнять:
Здесь имена
Magic::gnarl
,Magic::brugh
иMagic::kwpq
пришлось эксплицировать, поскольку сказать об этом невозможно: ПосколькуMagic
является шаблоном, то сама природа типаMagic
зависит отT
- могут существовать специализации, совершенно отличные от первичного шаблона, например.Что делает
Magic::gnarl
зависимым именем, так это тот факт, что мы находимся внутри определения шаблона, гдеT
неизвестно. Если бы мы использовалиMagic
, все было бы иначе, поскольку компилятор знает (обещаем!) полное определениеMagic
.(Если вы хотите проверить это самостоятельно, то вот пример определения
Magic
, который вы можете использовать. Извините за использованиеconstexpr
в специализации для краткости; если у вас старый компилятор, смело меняйте объявление статической константы-члена на старую форму, характерную для версии до С++11).Использование:
Ключевое слово
typename
необходимо, посколькуiterator
является зависимым типом отP
. Компилятор не может понять, относится лиiterator
к значению или к типу, поэтому он считает, что это значение, пока вы не скажетеtypename
. Он необходим в тех случаях, когда тип зависит от аргумента шаблона, в контексте, когда допустимы либо типы, либо значения. Например, в качестве базовых классовtypename
не нужен, поскольку базовый класс должен быть типом.По этому же поводу существует ключевое слово
template
, которое используется для того, чтобы сообщить компилятору, что некоторое зависимое имя является шаблонной функцией, а не значением.Ключевое слово typename необходимо в тех случаях, когда имя типа зависит от параметра шаблона (чтобы компилятор мог 'знать' семантику идентификатора (тип или значение), не имея при первом проходе полной таблицы символов).
Не в том же значении и несколько реже ключевое слово lone typename может быть полезно при использовании общих параметров шаблона: http://ideone.com/amImX.