Pourquoi une classe de modèle dérivée n’a-t-elle pas access aux identificateurs d’une classe de modèle de base?

Considérer:

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

Je ne suis pas capable de comstackr ceci avec GCC g ++ 3.4.4 (cygwin).

Avant de les convertir en modèles de classe, ils étaient non génériques et la classe dérivée pouvait voir les membres statiques de la classe de base. Cette perte de visibilité est-elle une exigence de la spécification C ++ ou existe-t-il un changement de syntaxe que je dois employer?

Je comprends que chaque instanciation de Base aura son propre membre statique ” ZEROFILL ” et ” NO_ZEROFILL “, que Base::ZEROFILL et Base::ZEROFILL sont des variables différentes, mais je ne sais pas vraiment se soucier; la constante est là pour la lisibilité du code. Je souhaitais utiliser une constante statique car celle-ci est plus sûre en termes de conflits de noms que de macro ou de global.

C’est une recherche en deux phases pour vous.

Base::NO_ZEROFILL (tous les identifiants de majuscules sont boo, sauf pour les macros, BTW) est un identifiant qui dépend de T
Puisque, lorsque le compilateur parsing d’abord le modèle, il n’y a pas encore de type substitué à T , le compilateur ne “sait” pas ce qu’est la Base . Il ne peut donc pas identifier les identificateurs que vous supposez être définis (il peut y avoir une spécialisation pour certains T que le compilateur ne verra que plus tard) et vous ne pouvez pas omettre la qualification de classe de base des identificateurs définis dans la classe de base.

C’est pourquoi vous devez écrire Base::NO_ZEROFILL (ou this->NO_ZEROFILL ). Cela indique au compilateur que NO_ZEROFILL est quelque chose dans la classe de base, qui dépend de T , et qu’il ne peut le vérifier que plus tard, lorsque le modèle est instancié. Il l’acceptera donc sans essayer de vérifier le code.
Ce code ne peut être vérifié que plus tard, lorsque le modèle est instancié en fournissant un paramètre réel pour T

Le problème que vous avez rencontré est dû aux règles de recherche de nom pour les classes de base dépendantes. 14.6 / 8 a:

Lorsque vous recherchez la déclaration d’un nom utilisé dans une définition de modèle, les règles de recherche habituelles (3.4.1, 3.4.2) sont utilisées pour les noms non dépendants. La recherche de noms en fonction des parameters du modèle est rescope jusqu’à ce que l’argument du modèle actuel soit connu (14.6.2).

(Ce n’est pas vraiment une “recherche en deux phases” – voir ci-dessous pour une explication de cela.)

Le point autour de 14.6 / 8 est que, dans la mesure où le compilateur est concerné, NO_ZEROFILL dans votre exemple est un identifiant et ne dépend pas du paramètre du modèle. Il est donc recherché selon les règles normales des 3.4.1 et 3.4.2.

Cette recherche normale ne recherche pas dans Base et donc NO_ZEROFILL est simplement un identificateur non déclaré. 14.6.2 / 3 a:

Dans la définition d’un modèle de classe ou d’un membre d’un modèle de classe, si une classe de base du modèle de classe dépend d’un paramètre de modèle, la scope de la classe de base n’est pas examinée lors de la recherche de nom non qualifiée. template ou member ou lors d’une instanciation du modèle de classe ou du membre.

Lorsque vous qualifiez NO_ZEROFILL avec Base:: essentiellement, vous changez de nom non dépendant en nom dépendant et lorsque vous le faites, vous en retardez la recherche jusqu’à ce que le modèle soit instancié.

Note latérale: Qu’est-ce que la recherche en deux phases:

 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’exemple ci-dessus est compilé comme suit. Le compilateur parsing le corps de la fonction de foo et voit qu’il y a un appel à la bar qui a un argument dépendant (c.-à-d. Un qui dépend du paramètre du modèle). A ce stade, le compilateur recherche la barre conformément à 3.4.1 et il s’agit de la “recherche de phase 1”. La recherche trouvera la fonction void bar (int) et sera stockée avec l’appel dépendant jusqu’à plus tard.

Lorsque le modèle est ensuite instancié (suite à l’appel de main ), le compilateur effectue ensuite une recherche supplémentaire dans la scope de l’argument, il s’agit de la “recherche de phase 2”. Ce cas qui aboutit à la recherche de void NS::bar(A const &) .

Le compilateur a deux surcharges pour la bar et il sélectionne entre eux, dans le cas ci-dessus appelant void NS::bar(A const &) .

Semble comstackr ok vs vs Avez-vous essayé:

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

Essayez ce programme

 #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< 

dans le T get(void){return this->x+2;} ligne u peut également utiliser l'opérateur de résolution de scope (: :). par exemple, essayez de remplacer la ligne par

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