Frage

Der folgende Code wird nicht mit gcc kompiliert, wohl aber mit Visual Studio:

template <typename T> class A {
public:
    T foo;
};

template <typename T> class B: public A <T> {
public:
    void bar() { cout << foo << endl; }
};

Ich erhalte die Fehlermeldung:

test.cpp:In der Member-Funktion „void B::bar()“:

test.cpp:11:Fehler:„foo“ wurde in diesem Bereich nicht deklariert

Aber es sollte sein!Wenn ich mich ändere bar Zu

void bar() { cout << this->foo << endl; }

dann es tut kompilieren, aber ich glaube nicht, dass ich das tun muss.Gibt es etwas in den offiziellen Spezifikationen von C++, dem GCC hier folgt, oder handelt es sich nur um eine Eigenart?

War es hilfreich?

Lösung

Das hat sich geändert gcc-3.4.Der C++-Parser wurde in dieser Version viel strenger – gemäß der Spezifikation, aber immer noch etwas nervig für Leute mit älteren Codebasen oder Multiplattform-Codebasen.

Andere Tipps

David Joyner hatte die Geschichte, hier ist der Grund.

Das Problem beim Kompilieren B<T> ist das seine Basisklasse? A<T> ist dem Compiler unbekannt, da es sich um eine Vorlagenklasse handelt, sodass der Compiler keine Möglichkeit hat, Mitglieder der Basisklasse zu kennen.

Frühere Versionen führten einige Rückschlüsse durch tatsächliches Parsen der Basisvorlagenklasse durch, aber ISO C++ gab an, dass dieser Rückschluss zu Konflikten führen kann, wo es keine geben sollte.

Die Lösung zum Verweisen auf ein Basisklassenmitglied in einer Vorlage ist die Verwendung von this (wie Sie es getan haben) oder benennen Sie die Basisklasse konkret:

template <typename T> class A {
public:
    T foo;
};

template <typename T> class B: public A <T> {
public:
    void bar() { cout << A<T>::foo << endl; }
};

Weitere Informationen unter gcc-Handbuch.

Wow.C++ überrascht mich immer wieder mit seiner Verrücktheit.

In einer Vorlagendefinition finden unqualifizierte Namen keine Mitglieder einer abhängigen Basis mehr (wie durch [temp.dep]/3 im C++-Standard angegeben).Zum Beispiel,

template <typename T> struct B {
  int m;
  int n;
  int f ();
  int g ();
};
int n;
int g ();
template <typename T> struct C : B<T> {
  void h ()
  {
    m = 0; // error
    f ();  // error
    n = 0; // ::n is modified
    g ();  // ::g is called
  }
};

Sie müssen die Namen abhängig machen, z.B.indem Sie ihnen this-> voranstellen.Hier ist die korrigierte Definition von C::h,

template <typename T> void C<T>::h ()
{
  this->m = 0;
  this->f ();
  this->n = 0
  this->g ();
}

Als alternative Lösung (leider nicht abwärtskompatibel mit GCC 3.3) können Sie stattdessen using-Deklarationen verwenden ->:

template <typename T> struct C : B<T> {
  using B<T>::m;
  using B<T>::f;
  using B<T>::n;
  using B<T>::g;
  void h ()
  {
    m = 0;
    f ();
    n = 0;
    g ();
  }
};

Das ist einfach total verrückt.Danke, David.

Hier ist der Abschnitt „temp.dep/3“ des Standards [ISO/IEC 14882:2003], auf den sie sich beziehen:

Wenn bei der Definition einer Klassenvorlage oder eines Mitglieds einer Klassenvorlage eine Basisklasse der Klassenvorlage von einem Vorlagenparameter abhängt, wird der Basisklassenbereich bei der unqualifizierten Namenssuche zum Zeitpunkt der Definition der Klasse nicht untersucht Vorlage oder Mitglied oder während einer Instanziierung der Klassenvorlage oder des Mitglieds.[Beispiel:

typedef double A; 
template<class T> class B { 
    typedef int A; 
}; 
template<class T> struct X : B<T> { 
    A a; // a has typedouble 
}; 

Der Typname A in der Definition von X<T> bindet an den Typedef-Namen, der im globalen Namespace-Bereich definiert ist, nicht an den Typedef-Namen, der in der Basisklasse definiert ist B<T>.] [Beispiel:

struct A { 
    struct B { /* ... */ }; 
    int a; 
    int Y; 
}; 
int a; 
template<class T> struct Y : T { 
    struct B { /* ... */ }; 
    B b; //The B defined in Y 
    void f(int i) { a = i; } // ::a 
    Y* p; // Y<T> 
}; 
Y<A> ya; 

Die Mitglieder A::B, A::a, Und A::Y des Vorlagenarguments A haben keinen Einfluss auf die Bindung von Namen in Y<A>. ]

Der Hauptgrund dafür, dass C++ hier nichts voraussetzen kann, ist, dass die Basisvorlage später für einen Typ spezialisiert werden kann.Fortsetzung des ursprünglichen Beispiels:

template<>
class A<int> {};

B<int> x; 
x.bar();//this will fail because there is no member foo in A<int>

VC implementiert im Gegensatz zu GCC keine zweiphasige Suche.Daher analysiert GCC Vorlagen, bevor sie instanziiert werden, und findet daher mehr Fehler als VC.In Ihrem Beispiel ist foo ein abhängiger Name, da er von „T“ abhängt.Sofern Sie dem Compiler nicht mitteilen, woher die Vorlage stammt, kann er die Gültigkeit der Vorlage überhaupt nicht überprüfen, bevor Sie sie instanziieren.Deshalb müssen Sie dem Compiler mitteilen, woher es kommt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top