MSVC, Clang i GCC nie zgadzają się na ten kod:
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 daje podobny błąd, a MSVC nie daje błędu.
Kto tu jest?
Przypuszczam, że jest to omówione w [class.member.lookup] , ale mam trudności ze zrozumieniem, co próbuje mi powiedzieć w tej sprawie. Proszę podać odpowiednie części i, jeśli to możliwe, wyjaśnić je prostym językiem angielskim.
PS: Zainspirowany tym pytaniem Dlaczego odniesienie do klasy podstawowej jest niejednoznaczne z klasą pochodną :: -operator?
PPS: Właściwie mam wątpliwości, czy Der1::Base
odnosi się do typu, który byłby Base
(a następnie Der2::Base
jest dokładnie tego samego typu), czy do podobiektu. Jestem przekonany, że jest to pierwszy, ale jeśli tak, to MSVC miałoby rację.
c++
language-lawyer
multiple-inheritance
diamond-problem
qualified-name
idclev 463035818
źródło
źródło
::Base
, ale prawdziwe pytanie wydaje się tutaj nieco inne. Istnieją dwa podobiekty typuBase
i oba mają elementBase::x
członkowski.Odpowiedzi:
Aby odpowiedzieć na pytanie w tytule, tak,
Derived1::Base
odwołuje się do nazwy wstrzykniętej klasy [class.pre]Base
i tak też jestDerived2::Base
. Oba odnoszą się do klasy::Base
.Teraz, jeśli
Base
miałoby statyczny elementx
, a następnie odnośnika odBase::x
byłaby jednoznaczna. Jest tylko jeden.Problem w tym przykładzie polega na tym, że
x
jest to element niestatyczny, iAllDer
ma dwa takie elementy. Możesz ujednoznacznić taki dostępx
, określając jednoznaczną klasę podstawową,AllDer
która ma tylko jednegox
członka.Derived1
jest jednoznaczną klasą podstawową i ma jednegox
członka, więcDerived1::x
jednoznacznie określa, który z dwóchx
członków wAllDer
tobie znaczy.Base
też ma tylko jednegox
członka, ale nie jest to jednoznaczna podstawaAllDer
. Każde wystąpienieAllDer
ma dwa podobiekty typuBase
. DlategoBase::x
jest niejednoznaczny w twoim przykładzie. A ponieważDerived1::Base
jest to tylko inna nazwaBase
, pozostaje to niejednoznaczne.[class.member.lookup] określa, że
x
jest sprawdzane w kontekście specyfikatora zagnieżdżonej nazwy, więc najpierw trzeba to rozwiązać. Rzeczywiście szukamyBase::x
, nieDerived1::x
, ponieważ zaczęliśmy od rozwiązaniaDerived1::Base
asBase
. Ta część kończy się sukcesem, jest tylko jedenx
wBase.
uwadze 12 w [class.member.lookup], który wyraźnie mówi, że użycie jednoznacznego wyszukiwania nazwy może nadal zawieść, gdy istnieje wiele podobiektów o tej samej nazwie.D::i
w tym przykładzie jest w zasadzie twójBase::x
.źródło
template <typname A,typename B> struct foo : A,B
z jakimś wymyślonym kodem, aby uzyskać dostęp do członków bazyA
iB
. W takim przypadku chcę otrzymać błądPowodem, dla którego możesz odwoływać się do nazwy klasy jako członka klasy, jest to, że cpp aliasuje ją dla wygodnego użycia, tak jakbyś pisał
using Base = ::Base;
w Base.Problem polega na tym, że
Der1::Base
jestBase
.Tak więc, kiedy piszesz
Der1::Base::x
, jest to to samo coBase::x
.źródło
using
jest napisana w standardzie i myślę, że to jest klucz do interpretacji tego, co mówi to wyrażenie.cl /c /Wall /WX /Od /MDd /Za /permissive- /std:c++17 main.cpp
jako wiersza poleceń, dostajęmain.cpp(7): error C2597: illegal reference to non-static member 'A::x'