2012-01-16 11 views
11

Tengo una clase base que se parece a la siguiente.Llamada al constructor base de la plantilla en la lista de inicialización del miembro error

template<typename T> 
class Base 
{ 
    public: 
     Base(int someValue); 

     virtual T someFunc() =0; 
}; 

template<typename T> 
Base<T>::Base(int someValue) 
{} 

Y luego lo siguiente.

#include "base.hpp" 

class Foo 
    : public Base<Foo> 
{ 
    public: 
     Foo(int someValue); 

     virtual Foo someFunc(); 
}; 

Foo::Foo(int someValue) 
    : Base(someValue) 
{} 

Recibo el siguiente error de gcc 4.2.1.

error: class ‘Foo’ does not have any field named ‘Base’ 

Debo mencionar esta compilación bien en mi caja de Fedora que está ejecutando gcc 4.6.2. Este error ocurre al compilar en mi máquina os x Lion.

Gracias de antemano por la ayuda.

EDITAR

problema parece que no estoy indicando el tipo de plantilla en la clase Foo al llamar al constructor. Lo siguiente corrige el error en os x.

: Base<Foo>(someValue, parent) 

EDITAR

Sí, esto se ve como un error. Lo que mencioné antes corrige el error bajo os x y el código compila bien en fedora con esa corrección. Veremos y veremos si hay una actualización de gcc en os x.

+0

[Qt se puede abstraer a partir de este completo.] (Http://ideone.com/tSWdI) –

+0

Dup? http://stackoverflow.com/questions/3829040/scope-problems-in-template-c –

Respuesta

8

Primero:

[C++11: 12.6.2/3]: A mem-inicializador-lista puede inicializar una clase base utilizando cualquier clase-o-decltype que indica que tipo de clase base.

[Ejemplo:

struct A { A(); }; 
typedef A global_A; 
struct B { }; 
struct C: public A, public B { C(); }; 
C::C(): global_A() { } // mem-initializer for base A 

ejemplo -fin]

Y Base debería haber un inyectada de clase-nombre válido para la base aquí (es decir, que puede usarlo en lugar de Base<T>):

[C++11: 14.6.1/1]:Al igual que las clases normales (sin plantilla), las plantillas de clase tienen un nombre-clase-inyectado (Cláusula 9). El nombre-clase-inyectado se puede utilizar como nombre-plantilla o nombre-tipo. Cuando se utiliza con una plantilla-argumento-lista, como plantilla-argumento para una plantilla-parámetro de plantilla , o como el identificador de final en el elaborado de tipo-especificador de una clase amigo declaración de plantilla, se refiere a la plantilla de clase en sí.De lo contrario, es equivalente a plantilla-nombre seguido de plantilla-parámetros de la plantilla de clase incluida en <>.

[C++11: 14.6.1/3]: El inyectado nombre-clase- de una plantilla de clase o especialización plantilla de clase se puede utilizar ya sea como un nombre-plantilla o un nombre de tipo dondequiera que está en el alcance. [Ejemplo:

template <class T> struct Base { 
    Base* p; 
}; 

template <class T> struct Derived: public Base<T> { 
    typename Derived::Base* p; // meaning Derived::Base<T> 
}; 

template<class T, template<class> class U = T::template Base> struct Third { }; 
Third<Base<int> > t; // OK: default argument uses injected-class-name as a template 

ejemplo -fin]

no he encontrado nada que indique que esto no se aplica en el ctor-inicializador, así que me gustaría decir que esto es un error del compilador.

Mi caso de prueba reducido fails in GCC 4.1.2 y GCC 4.3.4 pero succeeds in GCC 4.5.1 (C++11 mode). Parece ser resuelto por GCC bug 189; en the GCC 4.5 release notes:

G ++ ahora implementa DR 176. Anteriormente, G ++ no admitía el uso del nombre de clase inyectado de una clase base de plantilla como nombre de tipo y la búsqueda del nombre encontró la declaración de la plantilla en el ámbito adjunto. Ahora la búsqueda del nombre encuentra el nombre de la clase inyectada, , que puede usarse como tipo o como plantilla, dependiendo de independientemente de si el nombre es seguido por una lista de argumentos de la plantilla. Como resultado de este cambio, un código que fue aceptada con anterioridad puede ser mal formada, porque

  • El nombre-clase-inyectado no es accesible porque es a partir de una base privada, o
  • El injected- class-name no se puede usar como argumento para un parámetro de plantilla de plantilla.

En cualquiera de estos casos, el código se puede solucionar agregando un nombre-especificador-anidado para nombrar explícitamente la plantilla. El primero puede trabajar con con -fno-access-control; el segundo solo se rechaza con -pedantic.


Mi caso_prueba despojada con Qt abstrae a cabo:

template <typename T> 
struct Base { }; 

struct Derived : Base<Derived> { // I love the smell of CRTP in the morning 
    Derived(); 
}; 

Derived::Derived() : Base() {}; 
+0

Según tengo entendido, necesita agregar un parámetro de plantilla a la inicialización de la clase Base de Foos como tal: Foo :: Foo (int someValue, QObject * primario) : Base (someValue, principal) {} – Neox

+1

@Neox: ¿Por qué?¿Por qué el _injected-class-name_ de la base no es suficiente? –

+0

Creo que este es un [enlace al informe de error] (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=189) que se ha corregido de gcc 4.5 –

Cuestiones relacionadas