Perché una class template derivata non ha accesso agli identificatori di una class template di base?

Prendere in considerazione:

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(); } 

Non sono in grado di compilarlo con GCC g ++ 3.4.4 (cygwin).

Prima di convertirli in modelli di classi, erano non generici e la class derivata era in grado di vedere i membri statici della class base. È questa perdita di visibilità in un requisito delle specifiche C ++ o c’è una modifica della syntax che devo impiegare?

Capisco che ogni istanza di Base avrà il proprio membro statico ” ZEROFILL ” e ” NO_ZEROFILL “, che Base::ZEROFILL e Base::ZEROFILL sono variabili diverse, ma io in realtà cura; la costante è lì per la leggibilità del codice. Volevo utilizzare una costante statica perché è più sicura in termini di conflitti tra nomi piuttosto che macro o globali.

Questa è la ricerca in due fasi per te.

Base::NO_ZEROFILL (tutti gli identificatori di maiuscole sono boo, tranne per le macro, BTW) è un identificatore che dipende da T
Dal momento che, quando il compilatore analizza il modello per la prima volta, non esiste ancora un vero tipo sostituito da T , il compilatore non “sa” cosa sia Base . Quindi non può conoscere alcun identificatore che si assume essere definito in esso (potrebbe esserci una specializzazione per alcuni T che il compilatore vede solo in seguito) e non è ansible omettere la qualifica della class base dagli identificatori definiti nella class base.

Ecco perché devi scrivere Base::NO_ZEROFILL (o this->NO_ZEROFILL ). Questo dice al compilatore che NO_ZEROFILL è qualcosa nella class base, che dipende da T , e che può solo verificarlo in seguito, quando il modello viene istanziato. Lo accetterà quindi senza provare a verificare il codice.
Tale codice può essere verificato solo in un secondo momento, quando il modello viene istanziato fornendo un parametro effettivo per T

Il problema riscontrato è dovuto al nome delle regole di ricerca per le classi di base dipendenti. 14.6 / 8 ha:

Quando si cerca la dichiarazione di un nome utilizzato in una definizione di modello, le normali regole di ricerca (3.4.1, 3.4.2) vengono utilizzate per nomi non dipendenti. La ricerca dei nomi che dipendono dai parametri del template viene posticipata fino a quando non si conosce l’argomento template attuale (14.6.2).

(Questa non è realmente una “ricerca in 2 fasi” – vedi sotto per una spiegazione di ciò.)

Il punto 14.6 / 8 è che, per quanto riguarda il compilatore, NO_ZEROFILL nel tuo esempio è un identificatore e non dipende dal parametro del template. Viene quindi esaminato secondo le normali regole di 3.4.1 e 3.4.2.

Questa normale ricerca non ricerca all’interno di Base e quindi NO_ZEROFILL è semplicemente un identificatore non dichiarato. 14.6.2 / 3 ha:

Nella definizione di un modello di class o di un modello di class, se una class base del modello di class dipende da un parametro di modello, l’ambito della class di base non viene esaminato durante la ricerca di nome non qualificato nel punto di definizione della class modello o membro o durante un’istanza del modello o membro della class.

Quando si qualifica NO_ZEROFILL con Base:: in sostanza si sta cambiando da un nome non dipendente a uno dipendente e quando lo si fa si ritarda la sua ricerca fino a quando il modello viene istanziato.

Nota a margine: che cos’è la ricerca a 2 fasi:

 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); } 

L’esempio precedente è compilato come segue. Il compilatore analizza il corpo della funzione di foo e vede che c’è una chiamata alla bar che ha un argomento dipendente (cioè uno che dipende dal parametro template). A questo punto il compilatore cerca la barra come in 3.4.1 e questa è la “ricerca di fase 1”. La ricerca troverà la funzione void bar (int) e verrà memorizzata con la chiamata dipendente fino a un momento successivo.

Quando il modello viene quindi istanziato (come risultato della chiamata da main ), il compilatore esegue quindi una ricerca aggiuntiva nell’ambito dell’argomento, questa è la “ricerca di fase 2”. Questo caso che risulta nel trovare void NS::bar(A const &) .

Il compilatore ha due sovraccarichi per la bar e seleziona tra di essi, nel caso sopra chiamato void NS::bar(A const &) .

Sembra compilare ok a vs 2008. Hai provato:

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

Prova questo programma

 #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 T get(void){return this->x+2;} line u puoi anche usare la risoluzione dell'ambito (: 🙂 operator. per esempio, prova a sostituire la linea con

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