Accesso alla class template derivato ai dati membro della class base

Questa domanda è una promozione di quella richiesta in questa discussione .

Utilizzando le seguenti definizioni di class:

template  class Foo { public: Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg) { /* do something for foo */ } T Foo_T; // either a TypeA or a TypeB - TBD foo_arg_t _foo_arg; }; template  class Bar : public Foo { public: Bar (const foo_arg_t bar_arg, const a_arg_t a_arg) : Foo(bar_arg) // base-class initializer { Foo::Foo_T = T(a_arg); } Bar (const foo_arg_t bar_arg, const b_arg_t b_arg) : Foo(bar_arg) { Foo::Foo_T = T(b_arg); } void BarFunc (); }; template  void Bar::BarFunc () { std::cout << _foo_arg << std::endl; // This doesn't work - compiler error is: error: '_foo_arg' was not declared in this scope std::cout << Bar::_foo_arg << std::endl; // This works! } 

Quando si accede ai membri della class base della class template, sembra che io debba sempre qualificare esplicitamente i membri usando la syntax stile template di Bar::_foo_arg . c’è un modo per evitarlo? Una dichiarazione / direttiva ‘using’ può entrare in gioco in un metodo di class template per semplificare il codice?

Modificare:

Il problema dell’ambito viene risolto qualificando la variabile con questa -> syntax.

    Puoi usare this-> per chiarire che ti riferisci a un membro della class:

     void Bar::BarFunc () { std::cout << this->_foo_arg << std::endl; } 

    In alternativa puoi anche usare " using " nel metodo:

     void Bar::BarFunc () { using Bar::_foo_arg; // Might not work in g++, IIRC std::cout << _foo_arg << std::endl; } 

    Questo rende chiaro al compilatore che il nome del membro dipende dai parametri del modello in modo che cerchi la definizione di quel nome nelle posizioni giuste. Per maggiori informazioni vedi anche questa voce nel C ++ Faq Lite .

    Qui la class base non è una class base non dipendente (che significa una con un tipo completo che può essere determinata senza conoscere gli argomenti del template), e _foo_arg è un nome non dipendente. Il C ++ standard afferma che i nomi non dipendenti non sono ricercati nelle classi di base dipendenti.

    Per correggere il codice, è sufficiente rendere il nome _foo_arg dipendente perché i nomi dipendenti possono essere cercati solo al momento dell’istanziazione, e in quel momento sarà conosciuta la specializzazione di base esatta che deve essere esplorata. Per esempio:

     // solution#1 std::cout << this->_foo_arg << std::endl; 

    Un'alternativa consiste nell'introdurre una dipendenza utilizzando un nome qualificato:

     // solution#2 std::cout << Foo::_foo_arg << std::endl; 

    Bisogna fare attenzione con questa soluzione, perché se il nome non qualificato non dipendente viene utilizzato per formare una chiamata di funzione virtuale, la qualifica inibisce il meccanismo di chiamata virtuale e il significato del programma cambia.

    E puoi portare un nome da una class base dipendente nella class derivata using una volta:

     // solution#3 template  class Bar : public Foo { public: ... void BarFunc (); private: using Foo::_foo_arg; }; template  void Bar::BarFunc () { std::cout << _foo_arg << std::endl; // works } 

    Sembra funzionare correttamente in Visual c ++ 2008. Ho aggiunto alcune definizioni fittizie per i tipi che hai menzionato ma non ne ho fornito alcuna fonte. Il resto è esattamente come lo metti tu. Quindi una funzione principale per forzare BarFunc per essere istanziato e chiamato.

     #include  class streamable {}; std::ostream &operator<<(std::ostream &os, streamable &s) { return os; } class foo_arg_t : public streamable {}; class a_arg_t : public streamable {}; class b_arg_t : public streamable {}; template  class Foo { public: Foo (const foo_arg_t foo_arg) : _foo_arg(foo_arg) { /* do something for foo */ } T Foo_T; // either a TypeA or a TypeB - TBD foo_arg_t _foo_arg; }; template  class Bar : public Foo { public: Bar (const foo_arg_t bar_arg, const a_arg_t a_arg) : Foo(bar_arg) // base-class initializer { Foo::Foo_T = T(a_arg); } Bar (const foo_arg_t bar_arg, const b_arg_t b_arg) : Foo(bar_arg) { Foo::Foo_T = T(b_arg); } void BarFunc (); }; template  void Bar::BarFunc () { std::cout << _foo_arg << std::endl; std::cout << Bar::_foo_arg << std::endl; } int main() { Bar *b = new Bar(foo_arg_t(), a_arg_t()); b->BarFunc(); }