7 votes

Le membre de base dépendant du modèle n'est pas résolu correctement.

Cette question fait suite à Moving a member function from base class to derived class breaks the program for no obvious reason (c'est un exemple typique de pourquoi on ne devrait pas utiliser using namespace std;)

où les réponses ont suggéré de qualifier par this-> un nom de modèle dépendant (ce qui est en effet la méthode à suivre lorsqu'on fait référence à de tels membres dépendants). Cependant, il semble y avoir un problème, je vais donc fournir un exemple minimal reproduisant le problème.

Considérons le code :

#include 
#include 

using namespace std;

template
struct B
{
    T bitset{};
};

template
struct D : B
{
    bool foo()
    {
        return this->bitset < 32; 
    }
};

int main(){}

Live on Coliru

Le problème étrange est que même si this->bitset devrait faire référence au membre B::bitset, le compilateur est toujours confus et croit que nous essayons de faire référence à std::bitset. L'erreur apparaît à la fois avec gcc6 et clang3.7. Des idées sur pourquoi cela se produit ? Cela fonctionne en le qualifiant avec B::bitset cependant.

Erreur (verbatim) :

In member function 'bool D::foo(T, std::__cxx11::string)': cpp/scratch/minimal.cpp:24:22: error: invalid use of 'class std::bitset<1ul>'

MODIFICATION

Cela semble être un bug de parsing/lookup de nom pour moi. Si nous remplaçons < par tout autre opérateur de comparaison (merci @Leon pour la remarque), par exemple

return this->bitset == 32; 

le programme compile. Donc je suppose que dans this->bitset < 32 le parseur croit que nous essayons d'instancier un modèle (le signe <), et nous avons oublié de fermer le >. Mais je ne sais toujours pas si c'est un bug ou si c'est ainsi que le langage est censé fonctionner.

7voto

Useless Points 18909

tl;dr cela ressemble à une décision délibérée, spécifiquement pour soutenir la syntaxe alternative que vous avez déjà utilisée.

Une approximation du standardese ci-dessous:

this-> B <
         ^
  • cela pourrait être le début d'un identifiant de modèle ou un signe inférieur, donc vérifions les deux!
    1. this->B nomme quelque chose, mais c'est un modèle B, donc continuons
    2. B seul nomme également quelque chose, un modèle de classe B
    3. attends, ce sont la même chose! Cela signifie que nous utilisons this->B comme un qualificatif, et ce n'est pas un signe inférieur après tout

Dans l'autre cas,

this->bitset

procède de manière identique jusqu'à la troisième étape, lorsque l'on réalise qu'il y a deux choses différentes appelées bitset (un élément de classe de modèle et un modèle de classe), et abandonne simplement.


Ceci provient d'un brouillon de travail que j'ai sous la main, donc ce n'est pas forcément le plus récent, mais:

3.4.5 Accès aux membres de classe [basic.lookup.classref ]

1 Dans une expression d'accès à un membre de classe (5.2.5), si le jeton . ou -> est immédiatement suivi par un identifiant suivi par un <, l'identifiant doit être recherché pour déterminer si le < est le début d'une liste d'arguments de modèle (14.2) ou un opérateur inférieur. L'identifiant est d'abord recherché dans la classe de l'expression d'objet. Si l'identifiant n'est pas trouvé, il est ensuite recherché dans le contexte de l'ensemble de l'expression postfixe et doit nommer un modèle de classe. Si la recherche dans la classe de l'expression d'objet trouve un modèle, le nom est également recherché dans le contexte de l'ensemble de l'expression postfixe et

  • si le nom n'est pas trouvé, le nom trouvé dans la classe de l'expression d'objet est utilisé, sinon
  • si le nom est trouvé dans le contexte de l'ensemble de l'expression postfixe et ne nomme pas un modèle de classe, le nom trouvé dans la classe de l'expression d'objet est utilisé, sinon
  • si le nom trouvé est un modèle de classe, il doit se référer à la même entité que celle trouvée dans la classe de l'expression d'objet, sinon le programme est mal formé.

Donc, dans toute expression comme this->id < ..., il doit gérer les cas où id<... est le début d'un identifiant de modèle (comme this->B::bitset).

Il vérifie d'abord l'objet, mais si this->id trouve un modèle, des étapes supplémentaires s'appliquent. Et dans votre cas, this->bitset est vraisemblablement considéré comme un modèle car il dépend toujours de T, donc il trouve le std::bitset en conflit et échoue à la troisième puce ci-dessus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X