4 votes

Recherche de modèles de membres ambigus

Une réponse à cette question pregunta dit dans le code suivant :

#include <vector>
using std::vector;

struct foo {
  template<typename U>
  void vector();
};

int main() {
  foo f;
  f.vector<int>(); // ambiguous!
}

La dernière ligne de main est ambiguë, car le compilateur ne recherche pas seulement vector sur foo mais aussi comme un nom non qualifié à partir de l'intérieur de main . Il trouve donc à la fois std::vector y foo::vector . Pour résoudre ce problème, vous devez écrire

f.foo::vector<int>();

J'ai essayé ce programme sur tous les compilateurs C++ courants ( g++ , clang++ , vc++ et Intel C++ ) et tous les compilateurs compilent ce programme sans aucune erreur. Alors, pourquoi a-t-il dit qu'il y avait une ambiguïté dans ce programme ? Que dit la norme C++ à ce sujet ?

10voto

Shafik Yaghmour Points 42198

C'était le cas en C++03 mais cela a été corrigé en C++11. Nous pouvons même essayer ceci vivre dans godbolt avec clang en utilisant le drapeau -std=c++03 . Nous recevons un avertissement :

<source>:11:5: warning: lookup of 'vector' in member access expression is ambiguous; using member of 'foo' [-Wambiguous-member-template]

  f.vector<int>(); // ambiguous!
    ^

Documentation clang plus ancienne en utilisant le même exemple du rapport de défaut ci-dessous lors de la description de l'avertissement pour -Wambiguous-member-template .

Cela a été modifié par defect report 1111 : Suppression de la recherche à double portée des noms de modèles de membres qui explique le problème :

Selon 6.4.5 [basic.lookup.classref] paragraphe 1,

Dans une expression d'accès à un membre de classe (8.2.5 [expr.ref]), si le jeton . ou -> est immédiatement suivi d'un identifiant suivi d'un <, l'identificateur doit être recherché pour déterminer si le < est le est le début d'une liste d'arguments de modèle (17.2 [temp.names]) ou un opérateur moins que. L'identificateur est d'abord recherché dans la classe de l'expression de l'objet. Si l'identificateur n'est pas trouvé, il est ensuite recherché dans le contexte de toute l'expression postfixe et doit nommer un modèle de classe. nommer un modèle de classe. Si la recherche dans la classe de l'expression objet trouve un modèle, le nom est également recherché dans le contexte de l'expression de l'expression postfixe entière et

  • si le nom n'est pas trouvé, le nom trouvé dans la classe de l'expression de l'objet est utilisé, autrement

  • si le nom est trouvé dans le contexte de l'expression postfixe entière et ne nomme pas un modèle de classe, le nom trouvé dans la classe de l'expression de l'objet est utilisé, autrement

  • si le nom trouvé est un modèle de classe, il doit faire référence à la même entité que celle trouvée dans la classe de l'expression de l'objet, sinon le programme est mal formé.

Cela rend le texte suivant mal formé :

#include <set>
using std::set;
struct X {
  template <typename T> void set(const T& value);
};
void foo() {
  X x;
  x.set<double>(3.2);
}

C'est confus et inutile. Le compilateur a déjà effectué la recherche dans la portée de X, et la résolution évidemment correcte est celle-là, pas l'identifiant de la portée de l'expression postfixe. L'édition 305 a corrigé un problème similaire pour les noms de destructeurs mais a manqué les fonctions membres. membres.

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