2009-10-29 6 views
46

Estoy tratando de definir la clase base, que contiene solo typedef.Propagating 'typedef' basado en la clase derivada para 'template'

template<typename T> 
class A 
{ 
public: 
    typedef std::vector<T> Vec_t; 
}; 


template<typename T> 
class B : public A<T> 
{ 
private: 
    Vec_t v; // fails - Vec_t is not recognized 
}; 

¿Por qué en B Recibo un error que dice que Vec_t no es reconocido y necesito escribirlo explícitamente?

typename A<T>::Vec_t v; 
+0

duplicado exacto: http: // stackoverflow.com/questions/1567730/inheritance-and-templates-in-c-why-are-methods-invisible –

+10

Bueno, en realidad no es un duplicado exacto ya que la publicación que mencionas habla de un método mientras este habla de un tipo. –

+2

typename A :: Vec_t v; está bien. No hay necesidad de allí –

Respuesta

37

creo que esta pregunta es duplicado, pero no puedo encontrar ahora.C++ Estándar dice que debe calificar completamente nombre según 14.6.2/3:

En la definición de una plantilla de clase o un miembro de una plantilla de clase, si una clase base de la plantilla de clase depende de una plantilla -parameter, el alcance de la clase base no se examina durante la búsqueda de nombre no calificado ni en el punto de definición de la plantilla de clase o miembro, ni durante la instanciación de la plantilla o miembro de la clase.

UPD: He encontrado finalmente duplicado: here it is.

+13

Por cierto, siempre me molesta tener que 'volver a escribir todo' ... no es agradable, no es agradable en absoluto. –

+13

Por cierto, no necesita todos los argumentos de la plantilla y todo, cuando califica. Debido al nombre de clase inyectado, es suficiente escribir 'typename B :: Vec_t' –

7

Porque el compilador no está seguro de que Vec_t nombre un tipo. Por ejemplo, A<T> podría estar especializado para T=int a no tiene ese particular typedef.

+0

Para 'T' una variable de tipo,' A 'es meramente declarada, no tiene definición. Solo 'A ' donde 't' es un tipo (no una variable de tipo) se puede definir (especializando una definición de plantilla o por una especialización explícita). IOW, incluso si eliminara las especializaciones explícitas y parciales de plantillas de C++ (y no cambiara nada más), aún así no sería correcto. – curiousguy

2

Necesita calificar explícitamente el uso de Vec_t porque el compilador no sabe de dónde viene Vec_t.

No se puede asumir nada sobre la estructura de A, ya que la plantilla de clase A puede estar especializada. La especialización puede incluir un Vec_t que no es un typedef, o puede incluso no incluir un miembro Vec_t en absoluto.

1

Vec_t no es un nombre dependiente, y el compilador necesita saber de qué se trata sin instanciar ninguna plantilla (clase base en este caso). Es realmente no es diferente de:

template <class T> 
class X 
{ 
    std::string s; 
} 

Aquí también el compilador necesita saber acerca de std :: string incluso si X no se instancia, ya que el nombre no depende del argumento de plantilla T (hasta el compilador puede asumir).

En general, los typedefs en una clase base de plantilla parecen bastante inútiles para su uso en la clase derivada. Sin embargo, los typedefs son útiles para el usuario.

+0

¿Quiere decir 'clase X: T {' aquí? – curiousguy

26

Hay algo llamado dependiente y nondependent nombres en el caso de las plantillas.

Si el nombre depende del parámetro de plantilla T dependiente de su nombre y otros los que no dependen de parámetro T son independientes nombres.

Aquí está la regla: el compilador no mirada en las clases de base dependientes (como A) cuando se esté buscando no dependientes nombres (como Vec_t). Como resultado, el compilador no sabe que incluso existen y mucho menos son tipos.

compilador no puede asumir que Vec_t es un tipo hasta que se sabe T porque hay una especialización potencial de A<T> donde A<T>:: Vec_t es un es un miembro de datos

Así que la solución es utilizar nombretipo

typename A<T>::Vec_t v; ← good 

Te recomiendo que vayas a través de este https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types.

Viejo (roto) link: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18

+0

La tuya fue la única respuesta que pareció brindar una solución además de una explicación. Gracias. – Richard

+1

El enlace está roto –

+0

Te ofrezco un +1 si me notificas que has corregido el enlace. –

0

Este concepto se puede asociar con la forma en que usamos std::vector<T>. Por ejemplo, si tenemos un std::vector<int> Foo. Ahora, decidimos usar cualquiera de sus tipos de miembros, digamos un iterator. En este escenario podemos mencionar explícitamente

std::vector<int>::iterator foo_iterator; 

Del mismo modo, en su caso, con el fin de utilizar un tipo de miembro público Vec_t de template <typename T> class A, tiene que declarar explícitamente como

A<T>::Vec_t v; 
OR 
A<int>::Vec_t int_type; 
Cuestiones relacionadas