MSVC, Clang et GCC sont en désaccord sur ce code:
struct Base { int x; };
struct Der1 : public Base {};
struct Der2 : public Base {};
struct AllDer : public Der1, public Der2 {
void foo() {
Der1::Base::x = 5;
}
};
GCC:
<source>: In member function 'void AllDer::foo()':
<source>:10:21: error: 'Base' is an ambiguous base of 'AllDer'
10 | Der1::Base::x = 5;
| ^
Compiler returned: 1
Clang donne une erreur similaire et MSVC ne donne aucune erreur.
Qui est ici?
Je suppose que cela est couvert dans [class.member.lookup] , mais j'ai du mal à comprendre ce qu'il essaie de me dire pour ce cas. Veuillez citer les parties pertinentes et si possible expliquer en anglais simple.
PS: Inspiré par cette question Pourquoi la référence à la classe de base est-elle ambiguë avec la classe dérivée :: -operator trough?
PPS: En fait, mon doute est de savoir si se Der1::Base
réfère au type, qui serait Base
(et Der2::Base
est alors exactement le même type), ou au sous-objet. Je suis convaincu que c'est le premier, mais si c'est le dernier, alors MSVC aurait raison.
c++
language-lawyer
multiple-inheritance
diamond-problem
qualified-name
idclev 463035818
la source
la source
::Base
, mais la vraie question semble être légèrement différente ici. Il existe deux sous-objets de typeBase
, et les deux ont unBase::x
membre.Réponses:
Pour répondre à la question dans le titre, oui, fait
Derived1::Base
référence au nom de classe injecté [class.pre]Base
et il en est de mêmeDerived2::Base
. Les deux se réfèrent à la classe::Base
.Maintenant, si
Base
aurait un membre statiquex
, la recherche deBase::x
serait sans ambiguïté. Il n'y en a qu'un.Le problème dans cet exemple est qu'il
x
s'agit d'un membre non statique etAllDer
a deux de ces membres. Vous pouvez lever l' ambiguïté d'x
un tel accès en spécifiant une classe de base non ambiguëAllDer
qui n'a qu'un seulx
membre.Derived1
est une classe de base non ambiguë, et elle a unx
membre,Derived1::x
spécifie donc sans ambiguïté lequel des deuxx
membresAllDer
vous voulez dire.Base
a également un seulx
membre, mais ce n'est pas une base univoque deAllDer
. Chaque instance deAllDer
possède deux sous-objets de typeBase
. C'est doncBase::x
ambigu dans votre exemple. Et commeDerived1::Base
c'est juste un autre nom pourBase
, cela reste ambigu.[class.member.lookup] spécifie qu'il
x
est recherché dans le contexte du spécificateur de nom imbriqué, donc cela doit être résolu en premier. Nous recherchons en effetBase::x
, nonDerived1::x
, car nous avons commencé par résoudre enDerived1::Base
tant queBase
. Cette partie réussit, il n'y en a qu'unx
dans laBase.
note 12 dans [class.member.lookup] vous indique explicitement qu'une utilisation d'une recherche de nom sans ambiguïté peut toujours échouer lorsqu'il existe plusieurs sous-objets avec le même nom.D::i
dans cet exemple est fondamentalement votreBase::x
.la source
template <typname A,typename B> struct foo : A,B
avec un code artificiel pour accéder aux membres d'une base deA
etB
. Dans ce cas, je veux obtenir une erreurLa raison pour laquelle vous pouvez faire référence au nom de la classe en tant que membre de la classe est que cpp l'alias pour une utilisation pratique, comme si vous écriviez
using Base = ::Base;
dans Base.Le problème auquel vous êtes confronté
Der1::Base
est le suivantBase
.Ainsi, lorsque vous écrivez
Der1::Base::x
, c'est la même chose queBase::x
.la source
using
est écrite dans la norme, et je pense que c'est la clé pour interpréter ce que dit l'expression.cl /c /Wall /WX /Od /MDd /Za /permissive- /std:c++17 main.cpp
comme ligne de commande, j'obtiensmain.cpp(7): error C2597: illegal reference to non-static member 'A::x'