Je ne pense pas que ces éléments sont mal formés. Tout d'abord, pour using X::f2
, X
est recherché, et cela donnera sans ambiguïté le type de classe X
. Puis f2
dans X
est recherché, et ceci est non ambigu aussi (il n'est pas recherché dans D
!).
Le second cas travaillera pour la même raison.
Mais si vous appelf2
sur un objet D
, l'appel sera ambigu parce que le nom f2
est recherché dans tous les sous-objets de D
de type X
et D
a deux de ces sous-objets, et f2
est un non -statique fonction membre. La même raison vaut pour le second cas. Cela ne fait pas de différence pour ce que vous nommez f3
directement en utilisant Z::X
ou X
. Les deux désignent la classe X
.
Pour obtenir une ambiguïté pour la déclaration using, vous devez l'écrire différemment. Notez que dans C++ 0x using ThisClass::...;
n'est pas valide. C'est en C++ 03 cependant, tant que le nom entier fait référence à un membre de classe de base.
À l'inverse, si cela serait permis en C++ 0x, toute déclaration à l'aide serait également valable, parce que C++ 0x ne prend pas en compte pour les sous-objets de recherche de nom: D::f2
se réfère clairement à une seule déclaration (celui au X
). Voir DR #39 et le document final N1626.
struct D : Y, Z{
// ambiguous: f2 is declared in X, and X is a an ambiguous base class
using D::f2;
// still fine (if not referred to by calls/etc) :)
using Z::X::f3;
};
struct E : D {
// ambiguous in C++03
// fine in C++0x (if not referred to by an object-context (such as a call)).
using D::f2;
};
Le 03 C++ standard décrit ce aux paragraphes 10.2
et 3.4.3.1
.
Réponse pour Edit3:
Oui, GCC et VS2010 sont faux. trouble
se réfère au type trouvé par le nom de classe injecté de ::trouble
et à la classe imbriquée trouvée comme Y::trouble
. Le nom trouble
précédant le ::
est recherché en utilisant la recherche non qualifiée (par 3.4.1/7
, qui délègue à 10.2
dans la première puce) en ignorant les noms d'objet, de fonction et d'énumérateur (3.4.3/1
- il n'y a pas de noms dans ce cas, cependant). Il viole alors contre l » exigence 10.2
que:
If the resulting set of declarations are not all from sub-objects of the same type ... the program is ill-formed.
Il est possible que VS2010 et GCC interprètent libellé C++ 0x différemment que Comeau et mettre en œuvre rétroactivement libellé:
In a using-declaration used as a member-declaration, the nested-name-specifier shall name a base class of the class being defined.
Cette signifie que les classes autres que les bases sont considérées comme, mais que c'est une erreur si une classe autre que la base est nommée. Si le standard aurait l'intention d'ignorer les noms de classes autres que de base, il dirait que peut seulement ici, ou l'épeler explicitement (les deux pratiques sont terminées). La norme cependant n'est pas du tout conséquent avec son utilisation de doit et peut. Et GCC implémente le langage C++ 0x, car il rejette le code C++ 03 par ailleurs tout à fait correct, juste parce que la déclaration using contient son nom de classe.
Pour un exemple de la formulation peu claire, tenez compte de l'expression suivante:
a.~A();
Ceci est syntaxiquement ambiguë, car il peut être un appel de fonction de membre si a
est un objet de classe, mais il peut être un pseudo -destructor-call (qui est un no-op) si a
a un type scalaire (tel que int
). Mais ce que la norme dit est la syntaxe d'un appel pseudo-destructor et l'accès des membres de la classe à 5.2.4
et 5.2.5
respectivement
The left-hand side of the dot operator shall be of scalar type.
For the first option (dot) the type of the first expression (the object expression) shall be “class object” (of a complete type).
C'est le mauvais usage, car il ne voit pas clairement l'ambiguïté du tout. Il devrait utiliser "can only", et les compilateurs l'interprètent de cette façon. Cela a principalement des raisons historiques, comme l'a récemment dit un membre du comité sur Usenet. Voir The rules for the structure and drafting of International Standards, Annexe H.
Dans D, ajoutez une méthode qui appelle f2() pour voir ce qui se passe. –