Question

Cette question est une poursuite de celui demandé dans ce fil .

En utilisant les définitions de classe suivante:

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!
}

Lorsque vous accédez aux membres du modèle de classe de classe de base, il semble que je dois toujours se qualifier explicitement les membres en utilisant la syntaxe modèle de style de Bar<T>::_foo_arg. Y at-il un moyen d'éviter cela? Est-ce qu'un « utilisant » déclaration / directive entrent en jeu dans une méthode de classe de modèle pour simplifier le code?

Modifier:

La question de la portée est résolu en qualifiant la variable avec this-> syntaxe.

Était-ce utile?

La solution

Vous pouvez utiliser this-> pour préciser que vous faites référence à un membre de la classe:

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

utiliser Sinon, vous pouvez aussi "using" dans la méthode:

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

Il est donc clair au compilateur que le nom du membre dépend des paramètres du modèle afin qu'il recherche la définition de ce nom dans les bons endroits. Pour de plus amples informations, voir aussi cette entrée dans le répertoire C ++ Faq Lite .

Autres conseils

Ici, la classe de base n'est pas une classe de base non-dépendante (ce qui signifie que l'un avec un type complet qui peut être déterminé sans connaître les arguments de modèle), et _foo_arg est un nom non dépendantes. C ++ standard indique que les noms ne sont pas non dépendantes recherchés dans les classes de base dépendantes.

Pour corriger le code, il suffit de rendre le nom _foo_arg dépendante parce que les noms dépendants peuvent être consultés seulement au moment de l'instanciation, et à ce moment la spécialisation exacte de base qui doit être explorée sera connue. Par exemple:

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

Une autre solution consiste à introduire une dépendance à l'aide d'un nom qualifié:

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

Il faut prendre soin de cette solution, car si le nom non qualifié est utilisé pour non dépendantes former un appel de fonction virtuelle, puis la qualification empêche le mécanisme d'appel virtuel et la signification des changements de programme.

Et vous pouvez apporter un nom d'une classe de base dépendant de la classe dérivée une fois par 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
}

Semble fonctionner correctement dans Visual C ++ 2008. J'ai ajouté quelques définitions factices pour les types que vous avez mentionnés, mais donné aucune source pour. Le reste est exactement comme vous le dites. Ensuite, une fonction principale pour forcer BarFunc à instancier et a appelé.

#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();
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top