template example c++ templates syntax typename

c++ - example - ¿Cuándo es necesaria la palabra clave "typename"?



typename c++ (3)

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 K> class C { struct P {}; vector<P> vec; void f(); }; template<class K> void C<K>::f() { typename vector<P>::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"?


La palabra clave typename es necesaria porque iterator es un tipo dependiente en P El compilador 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 compilador 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 compilador 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 genéricos de plantilla: http://ideone.com/amImX

#include <string> #include <list> #include <vector> template <template <typename, typename> class Container, template <typename> class Alloc = std::allocator> struct ContainerTests { typedef Container<int, Alloc<int> > IntContainer; typedef Container<std::string, Alloc<int> > StringContainer; // void DoTests() { IntContainer ints; StringContainer strings; // ... etc } }; int main() { ContainerTests<std::vector> t1; ContainerTests<std::list> t2; t1.DoTests(); t2.DoTests(); }


Respuesta corta: siempre que se haga referencia a un nombre anidado que es un nombre dependiente , es decir, anidado 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 <typename> struct Magic; // defined somewhere else template <typename T> struct A { static const int value = Magic<T>::gnarl; // assumed "value" typedef typename Magic<T>::brugh my_type; // decreed "type" // ^^^^^^^^ void foo() { Magic<T>::template kwpq<T>(1, ''a'', .5); // decreed "template" // ^^^^^^^^ } };

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

Lo que hace que Magic<T>::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<int> , esto sería diferente, ya que el compilador conoce (¡lo promete!) La definición completa de Magic<int> .

(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 compilador antiguo, siéntase libre de cambiar la declaración constante de miembro estático a la antigua estilo de forma pre-C ++ 11)

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

Uso:

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