Warum hat eine abgeleitete Vorlagenklasse keinen Zugriff auf die Bezeichner einer Basisvorlagenklasse?

Erwägen:

template  class Base { public: static const bool ZEROFILL = true; static const bool NO_ZEROFILL = false; } template  class Derived : public Base { public: Derived( bool initZero = NO_ZEROFILL ); // NO_ZEROFILL is not visible ~Derived(); } 

Ich kann das nicht mit GCC g ++ 3.4.4 (cygwin) kompilieren.

Vor dem Konvertieren in classnvorlagen waren diese nicht generisch und die abgeleitete class konnte die statischen Member der Basisklasse sehen. Ist der Verlust der Sichtbarkeit in einer Anforderung der C ++ – Spezifikation oder gibt es eine Syntaxänderung, die ich verwenden muss?

Ich verstehe, dass jede Instanz von Base ihre eigenen statischen Member ” ZEROFILL ” und ” NO_ZEROFILL ” haben wird, dass Base::ZEROFILL und Base::ZEROFILL verschiedene Variablen sind, aber ich nicht wirklich Pflege; die Konstante ist da für die Lesbarkeit des Codes. Ich wollte eine statische Konstante verwenden, da dies hinsichtlich Namenskonflikten sicherer ist als ein Makro oder global.

   

Das ist ein Zweiphasen-Lookup für Sie.

Base::NO_ZEROFILL (alle Base::NO_ZEROFILL Bezeichner sind boo, außer für Makros, BTW) ist ein Bezeichner, der von T abhängt.
Da, wenn der Compiler zuerst die Vorlage analysiert, kein aktueller Typ für T vorhanden ist, “weiß” der Compiler nicht, was Base ist. Daher kann es keine Identifikatoren kennen, von denen Sie annehmen, dass sie darin definiert sind (es könnte eine Spezialisierung für einige T s geben, die der Compiler nur später sieht) und Sie können die Basisklassenqualifikation nicht aus den in der Basisklasse definierten Identifikatoren auslassen.

Deshalb müssen Sie Base::NO_ZEROFILL (oder this->NO_ZEROFILL ) this->NO_ZEROFILL . Das teilt dem Compiler mit, dass NO_ZEROFILL etwas in der Basisklasse ist, die von T abhängt, und dass es nur später verifizieren kann, wenn die Vorlage instanziiert wird. Es akzeptiert es daher, ohne zu versuchen, den Code zu überprüfen.
Dieser Code kann erst später verifiziert werden, wenn die Vorlage instanziiert wird, indem ein tatsächlicher Parameter für T bereitgestellt wird.

Das Problem, auf das Sie gestoßen sind, beruht auf Namenssuchregeln für abhängige Basisklassen. 14.6 / 8 hat:

Bei der Suche nach der Deklaration eines Namens, der in einer Schablonendefinition verwendet wird, werden die üblichen Suchregeln (3.4.1, 3.4.2) für nicht abhängige Namen verwendet. Das Nachschlagen von Namen, die von den Vorlagenparametern abhängig sind, wird verschoben, bis das tatsächliche Vorlagenargument bekannt ist (14.6.2).

(Dies ist nicht wirklich “2-Phasen-Lookup” – siehe unten für eine Erklärung davon.)

Der Punkt um 14.6 / 8 ist, dass in NO_ZEROFILL auf den Compiler NO_ZEROFILL in Ihrem Beispiel ein Bezeichner ist und nicht vom Template-Parameter abhängig ist. Es wird daher nach den normalen Regeln in 3.4.1 und 3.4.2 gesucht.

Diese normale Suche sucht nicht innerhalb von Base und daher ist NO_ZEROFILL einfach ein nicht deklarierter Bezeichner. 14.6.2 / 3 hat:

Wenn in der Definition einer classnvorlage oder eines Members einer classnvorlage eine Basisklasse der classnvorlage von einem Vorlagenparameter abhängt, wird der Basisklassenbereich nicht während der Suche nach unqualifiziertem Namen entweder zum Zeitpunkt der Definition der class überprüft Vorlage oder Mitglied oder während einer Instanziierung der classnvorlage oder des Members.

Wenn Sie NO_ZEROFILL mit Base:: qualifizieren, NO_ZEROFILL Sie es im Wesentlichen von einem nicht abhängigen Namen in einen abhängigen Namen, und wenn Sie dies tun, verzögern Sie seine Suche, bis die Vorlage instanziiert wird.

Randnotiz: Was ist 2-Phasen-Lookup:

 void bar (int); template  void foo (T const & t) { bar (t); } namespace NS { struct A {}; void bar (A const &); } int main () { NS::A a; foo (a); } 

Das obige Beispiel wird wie folgt zusammengestellt. Der Compiler analysiert den functionskörper von foo und sieht, dass es einen Aufruf für einen bar gibt, der ein abhängiges Argument hat (dh eines, das vom Vorlagenparameter abhängig ist). An dieser Stelle sucht der Compiler nach 3.4.1 nach oben und dies ist der “Phase 1 Lookup”. Die Suche findet die function void bar (int) und diese wird mit dem abhängigen Aufruf bis später gespeichert.

Wenn die Vorlage dann instanziiert wird (als ein Ergebnis des Aufrufs von main ), führt der Compiler dann eine zusätzliche Suche im Bereich des Arguments durch, dies ist die “Phase 2-Suche”. Dieser Fall führt zum Auffinden von void NS::bar(A const &) .

Der Compiler hat zwei Überladungen für den bar und wählt zwischen ihnen aus, im obigen Fall ruft er void NS::bar(A const &) .

Scheint, kompilieren in vs 2008. Haben Sie versucht:

 public: Derived( bool initZero = Base::NO_ZEROFILL ); 

Probieren Sie dieses Programm aus

 #include using namespace std; template  class base{ public: T x; base(T a){x=a;} virtual T get(void){return x;} }; template  class derived:public base{ public: derived(T a):base(a){} T get(void){return this->x+2;} }; int main(void){ base ob1(10); cout<  ob(10); cout<  

in der T get(void){return this->x+2;} Zeile kann man auch die scope resolution (: 🙂 Operator benutzen. Versuchen Sie zum Beispiel, die Zeile mit zu ersetzen

 T get(void){return base::x+2;}