Domanda

Questa domanda è un perseguimento di quello chiesto in questa discussione .

Utilizzando le definizioni di classe seguente:

template <class T>
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 T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::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<T>::_foo_arg << std::endl;   // This works!
}

Quando si accede i membri della classe base del modello di classe, sembra che devo sempre qualificare esplicitamente i membri utilizzando la sintassi modello stile di Bar<T>::_foo_arg. c'è un modo per evitarlo? Può un 'utilizzando' istruzione / direttiva entrare in gioco in un metodo di classe modello per semplificare il codice?

Modifica

Il problema viene risolto ambito qualificando la variabile con this-> sintassi.

È stato utile?

Soluzione

È possibile utilizzare this-> mettere in chiaro che ci si riferisce a un membro della classe:

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

In alternativa è possibile utilizzare anche "using" nel metodo:

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

Ciò rende chiaro al compilatore che il nome del membro dipende dai parametri del modello in modo che cerca la definizione di tale nome nei posti giusti. Per ulteriori informazioni vedere anche questa voce nel C ++ Faq Lite .

Altri suggerimenti

Qui la classe base non è una classe base nondependent (il che significa che uno con un tipo completo che può essere determinato senza conoscere gli argomenti di template), e _foo_arg è un nome nondependent. C ++ standard dice che i nomi nondependent non si vedono in classi di base a carico.

Per correggere il codice, è sufficiente fare il nome _foo_arg dipendente perché i nomi di dipendenti possono essere consultati solo al momento di istanziazione, e in quel momento sarà noto l'esatto specializzazione di base che deve essere esplorato. Ad esempio:

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

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

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

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

E si può portare un nome da una classe di base dipendente nella classe derivata da una volta using:

// solution#3
template <class T>
class Bar : public Foo<T> {
public:
    ...
    void BarFunc ();
private:
    using Foo<T>::_foo_arg;
};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl;   // works
}

sembra funzionare bene in Visual C ++ 2008. Ho aggiunto alcune definizioni fittizi per i tipi che lei ha citato, ma dato alcuna fonte per. Il resto è esattamente come dici tu. Poi una funzione principale per costringere BarFunc da un'istanza e chiamato.

#include <iostream>

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 T>
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 T>
class Bar : public Foo<T> {
public:
    Bar (const foo_arg_t bar_arg, const a_arg_t a_arg)
    : Foo<T>(bar_arg)   // base-class initializer
    {

        Foo<T>::Foo_T = T(a_arg);
    }

    Bar (const foo_arg_t bar_arg, const b_arg_t b_arg)
    : Foo<T>(bar_arg)
    {
        Foo<T>::Foo_T = T(b_arg);
    }

    void BarFunc ();

};

template <class T>
void Bar<T>::BarFunc () {
    std::cout << _foo_arg << std::endl; 
    std::cout << Bar<T>::_foo_arg << std::endl;   
}

int main()
{
    Bar<a_arg_t> *b = new Bar<a_arg_t>(foo_arg_t(), a_arg_t());
    b->BarFunc();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top