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!
}