Короткая версия, которую вам нужно сделать typename X::Y
, когда X равен или зависит от параметра шаблона. Пока X не известен, компилятор не может определить, является ли Y типом или значением. Поэтому вы должны добавить typename
, чтобы указать, что это тип.
Например:
template <typename T>
struct Foo {
typename T::some_type x; // T is a template parameter. `some_type` may or may not exist depending on what type T is.
};
template <typename T>
struct Foo {
typename some_template<T>::some_type x; // `some_template` may or may not have a `some_type` member, depending on which specialization is used when it is instantiated for type `T`
};
Как указывает sbi в комментариях, причина неоднозначности заключается в том, что Y
может быть статическим членом, перечислением или функцией. Не зная типа X
, мы не можем сказать.
Стандарт определяет, что компилятор должен предполагать, что это значение, если оно явно не помечено как тип с помощью ключевого слова typename
.
И, похоже, комментаторы действительно хотят, чтобы я упомянул и еще один связанный случай:;)
Если зависимое имя является шаблоном члена функции, и вы вызываете его с явным аргументом шаблона (например, foo.bar<int>()
), вам необходимо добавить ключевое слово template
перед именем функции, как в foo.template bar<int>()
.
Причина этого в том, что без ключевого слова template компилятор предполагает, что bar
является значением, и вы хотите вызвать для него оператор меньше чем (operator<
).