¿Cuándo es necesaria la palabra clave “typename”?

Posible duplicado:
Oficialmente, ¿para qué sirve typename?
¿Dónde y por qué tengo que poner la plantilla y las palabras clave typename?

considere el siguiente código:

template class C { struct P {}; vector

vec; void f(); }; template void C::f() { typename vector

::iterator p = vec.begin(); }

¿Por qué la palabra clave “typename” es necesaria en este ejemplo? ¿Hay algún otro caso donde se deba especificar “typename”?

Respuesta corta: siempre que se haga referencia a un nombre nested que es un nombre dependiente , es decir, nested dentro de una instancia de plantilla con un parámetro desconocido.

Respuesta larga: hay tres niveles de entidades en C ++: valores, tipos y plantillas. Todos esos pueden tener nombres, y el nombre solo no le dice qué nivel de entidad es. Por el contrario, la información sobre la naturaleza de la entidad de un nombre debe inferirse del contexto.

Siempre que esta inferencia sea imposible, debes especificarla:

 template  struct Magic; // defined somewhere else template  struct A { static const int value = Magic::gnarl; // assumed "value" typedef typename Magic::brugh my_type; // decreed "type" // ^^^^^^^^ void foo() { Magic::template kwpq(1, 'a', .5); // decreed "template" // ^^^^^^^^ } }; 

Aquí los nombres Magic::gnarl , Magic::brugh y Magic::kwpq tuvieron que ser explícitos, porque es imposible saberlo: ya que Magic es una plantilla, la naturaleza misma del tipo Magic depende de T ; puede haber especializaciones que son completamente diferentes de la plantilla principal, por ejemplo.

Lo que hace que Magic::gnarl un nombre dependiente es el hecho de que estamos dentro de una definición de plantilla, donde T es desconocido. Si hubiéramos utilizado Magic , esto sería diferente, ya que el comstackdor conoce (¡lo promete!) La definición completa de Magic .

(Si desea probar esto usted mismo, aquí hay una definición de muestra de Magic que puede usar. Perdón por el uso de constexpr en la especialización por brevedad; si tiene un comstackdor antiguo, siéntase libre de cambiar la statement constante de miembro estático a la antigua estilo de forma pre-C ++ 11)

 template  struct Magic { static const T gnarl; typedef T & brugh; template  static void kwpq(int, char, double) { T x; } }; template <> struct Magic { // note that `gnarl` is absent static constexpr long double brugh = 0.25; // `brugh` is now a value template  static int kwpq(int a, int b) { return a + b; } }; 

Uso:

 int main() { A a; a.foo(); return Magic::kwpq(2, 3); // no disambiguation here! } 

La palabra clave typename es necesaria porque iterator es un tipo dependiente en P El comstackdor no puede adivinar si el iterator refiere a un valor o un tipo, por lo que asume que es un valor a menos que grite typename . Se necesita siempre que haya un tipo que dependa de un argumento de plantilla, en un contexto en el que los tipos o valores serían válidos. Por ejemplo, como clases base, typename no es necesario ya que una clase base debe ser un tipo.

Sobre el mismo tema, hay una palabra clave de template usa para que el comstackdor sepa que algún nombre dependiente es una función de plantilla en lugar de un valor.

La palabra clave typename es necesaria siempre que el nombre de un tipo dependa de un parámetro de plantilla (para que el comstackdor pueda ‘conocer’ la semántica de un identificador ( tipo o valor ) sin tener una tabla de símbolos completa en el primer pase).


No en el mismo sentido, y un poco menos común, la palabra clave lone typename también puede ser útil cuando se usan parámetros generics de plantilla: http://ideone.com/amImX

 #include  #include  #include  template