2010-10-24 5 views
29

Pourquoi ne peut pas un compilateur C++ reconnaître que g() et b sont membres hérités de Superclass comme on le voit dans ce code:accès membres protégés de superclasse en C++ avec des modèles

template<typename T> struct Superclass { 
protected: 
    int b; 
    void g() {} 
}; 

template<typename T> struct Subclass : public Superclass<T> { 
    void f() { 
    g(); // compiler error: uncategorized 
    b = 3; // compiler error: unrecognized 
    } 
}; 

Si je simplifie Subclass et juste hériter de Subclass<int> puis il compile. Il compile également lorsqu'il qualifie entièrement g() en tant que Superclass<T>::g() et Superclass<T>::b. J'utilise LLVM GCC 4.2.

Remarque: Si je fais g() et b public dans la superclasse, il échoue toujours avec la même erreur.

Répondre

39

Cela peut être modifié en tirant les noms dans le champ d'application actuel à l'aide using:

template<typename T> struct Subclass : public Superclass<T> { 
    using Superclass<T>::b; 
    using Superclass<T>::g; 

    void f() { 
    g(); 
    b = 3; 
    } 
}; 

Ou en qualifiant le nom via l'accès pointeur this:

template<typename T> struct Subclass : public Superclass<T> { 
    void f() { 
    this->g(); 
    this->b = 3; 
    } 
}; 

Ou, comme vous avez déjà remarqué, en qualifiant le nom complet.

La raison pour laquelle cela est nécessaire est que C++ ne considère pas les modèles de super-classe pour la résolution de noms (car ils sont alors des noms dépendants et les noms dépendants ne sont pas pris en compte). Cela fonctionne lorsque vous utilisez Superclass<int> parce que ce n'est pas un modèle (c'est instantiation d'un modèle) et donc ses noms imbriqués ne sont pas dépendants noms.

+6

Les compilateurs de Microsoft ne respectent pas cette règle. Je suis en colère –

+0

Merci, cela fonctionne. – andrewz

+8

@Armen: seulement cette règle? Wow, ça a vraiment * s'est * amélioré. :-D –

14

La réponse de Konrad ne demande pas ou ne répond pas au «pourquoi» final de tout cela. Ce n'est pas seulement le comité C++ qui dit arbitrairement «Hé, abandonne les noms dépendants, personne ne les aime de toute façon». Plutôt, le compilateur vérifie les templates avant même qu'ils ne soient instanciés, et il ne peut avoir aucune signification de g() ou de b jusqu'à ce qu'il connaisse T, car il ne peut pas - en général - choisir entre des spécialisations possibles de la classe de base (par exemple SuperClass<X> peut avoir int b tandis que SuperClass<Y> a void b() et SuperClass<Z> n'a pas du tout b). Les formes les plus explicites disent juste "croyez-moi - cela doit provenir de la classe de base au moment de l'instanciation (sinon il y aura alors une erreur de compilation)".

+0

Kinda a du sens, mais c'est certainement l'une des "caractéristiques" les plus obscures de la modélisation. – ChrisWue

+0

@ChrisWue: il y a beaucoup de compétition dans cette course! ;-) –

+0

GCC était capable de gérer cela dans le passé (années 1990), mais plus tard, au fur et à mesure de l'évolution de C++, il a été modifié. Je suppose que la façon dont il a été géré a causé des problèmes dans certains cas, ce qui explique pourquoi il a été modifié. – PolarBear2015

Questions connexes