La versión corta que necesita hacer typename X::Y
cuando X es o depende de un parámetro de plantilla. Hasta que se conozca X, el compilador no puede decir si Y es un tipo o un valor. Por lo tanto, debe agregar typename
para especificar que es un tipo.
Por ejemplo:
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`
};
Como sbi señala en los comentarios, la causa de la ambigüedad es que Y
podría ser un miembro estático, una enumeración o una función. Sin saber el tipo de X
, no podemos decirlo. El estándar especifica que el compilador debe suponer que es un valor a menos que esté explícitamente etiquetado como un tipo mediante la palabra clave typename
.
Y parece que los comentaristas realmente quieren que mencione otro caso relacionado, así:;)
Si el nombre del dependiente es una plantilla miembro de la función, y se le llama con un argumento de plantilla explícita (foo.bar<int>()
, por ejemplo), debe agregar la palabra clave template
antes del nombre de la función, como en foo.template bar<int>()
.
La razón de esto es que sin la palabra clave de la plantilla, el compilador supone que bar
es un valor, y desea invocar al operador menor que (operator<
) en él.
Te recomiendo que leas la plantilla de preguntas frecuentes: http://womble.decadentplace.org.uk/c++/template-faq.html –