language c++ inheritance templates

c++ - language - Accediendo a la variable heredada de la clase principal con plantilla



contains liquid (2)

Considera el siguiente código:

template<class T> class Foo { public: Foo() { a = 1; } protected: int a; }; template<class T> class Bar : public Foo<T> { public: Bar() { b = 4; }; int Perna(int u); protected: int b; }; template<class T> int Bar<T>::Perna(int u) { int c = Foo<T>::a * 4; // This works return (a + b) * u; // This doesn''t }

g ++ 3.4.6, 4.3.2 y 4.1.2 dan error

test.cpp: In member function `int Bar<T>::Perna(int)'': test.cpp:25: error: `a'' was not declared in this scope

g ++ 2.96 y MSVC 6, 7, 7.1, 8 y 9 lo aceptan, al igual que (al menos) los antiguos compiladores Intel y SGI c ++.

¿El nuevo compilador Gnu C ++ obedece el estándar o no? Si lo hacen, ¿cuál es la lógica detrás de la herencia de la clase que no puede ver una variable heredada protegida?

Además, si hay

int A() { return a; }

en Foo, obtengo un error

test.cpp:25: error: there are no arguments to A that depend on a template parameter, so a declaration of A must be available test.cpp:25: error: (if you use -fpermissiveâ, G++ will accept your code, but allowing the use of an undeclared name is deprecated)

cuando intento usarlo en una función miembro de Bar. También me parece curioso: Bar hereda Foo, así que creo que es obvio que A () en el alcance de Bar es Foo :: A ().


El mensaje de error que GCC muestra muestra que su versión de GCC aún tenía un error que solo se resuelve en las versiones de troncales de GCC4.7. Las versiones anteriores, incluyendo GCC4.1 aceptarán felizmente el siguiente código

template<typename T> struct A { void f(int) { } }; template<typename T> struct B : A<T> { void g() { T t = 0; f(t); } }; int main() { B<int> b; b.g(); }

GCC buscará f en f(t) dentro de la clase base A<T> y encontrará la declaración en la clase base. GCC lo hace porque f es dependiente , porque hay argumentos para f que "dependen de un parámetro de plantilla" (¡mira el mensaje de error que te dio!). Pero el estándar prohíbe a GCC hacer eso por dos razones

  1. El Estándar dice que el uso de nombres no calificados nunca encontrará una declaración en una clase base dependiente, sin importar si el nombre es dependiente .

  2. El estándar dice que la búsqueda dependiente de un nombre de función en el momento de instanciación solo hará ADL.

GCC 4.7 implementa el estándar correctamente en ese sentido.


Las últimas versiones de GCC implementan correctamente el estándar.

El estándar especifica que los nombres no calificados en una plantilla no son dependientes y deben buscarse cuando se define la plantilla. La definición de una clase base dependiente se desconoce en ese momento (pueden existir especializaciones de la plantilla de la clase base) por lo que los nombres no calificados no se pueden resolver.

Esto es cierto para los nombres de variables y funciones declarados en la clase base.

Como ha observado, la solución es proporcionar el nombre calificado de la variable o función, o proporcionar una declaración de "uso". P.ej

template<class T> int Bar<T>::Perna(int u) { int c = Foo<T>::a * 4; // This works c = this->a * 4; // and this using Foo<T>::a; c = a * 4; // and with ''using'', so should this }

(En realidad, no estoy 100% seguro de la sintaxis correcta para la versión de uso y no puedo probar desde aquí, pero se entiende).