MSVC, Clang und GCC sind sich in diesem Code nicht einig:
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 gibt einen ähnlichen Fehler aus und MSVC gibt keinen Fehler aus.
Wer ist hier richtig?
Ich nehme an, dass dies in [class.member.lookup] behandelt wird , aber ich habe Schwierigkeiten zu verstehen, was es mir für diesen Fall zu sagen versucht. Bitte zitieren Sie die relevanten Teile und erklären Sie diese nach Möglichkeit in einfachem Englisch.
PS: Inspiriert von dieser Frage Warum ist der Verweis auf die Basisklasse mit der von :: -operator durch abgeleiteten Klasse nicht eindeutig?
PPS: Eigentlich bezweifle ich, ob es Der1::Base
sich um den Typ handelt, der wäre Base
(und dann Der2::Base
genau der gleiche Typ ist), oder um das Unterobjekt. Ich bin überzeugt, dass es das erste ist, aber wenn es das letztere ist, dann wäre MSVC richtig.
quelle
::Base
, aber die eigentliche Frage scheint hier etwas anders zu sein. Es gibt zwei Unterobjekte vom TypBase
und beide haben einBase::x
Mitglied.Antworten:
Um die Frage im Titel zu beantworten,
Derived1::Base
verweist yes auf den Namen der injizierten Klasse [class.pre]Base
und dies auchDerived2::Base
. Beide beziehen sich auf die Klasse::Base
.Wenn
Base
nun ein statisches Mitglied vorhanden wäre, wärex
die SucheBase::x
nach eindeutig. Es gibt nur einen.Das Problem in diesem Beispiel ist , dass
x
ein nicht-statisches Element undAllDer
hat zwei solche Mitglieder. Sie können einen solchen Zugriff eindeutig definieren,x
indem Sie eine eindeutige Basisklasse angeben,AllDer
die nur einx
Mitglied hat.Derived1
ist eine eindeutige Basisklasse und hat einx
Mitglied.Derived1::x
Gibt also eindeutig an, welches der beidenx
Mitglieder inAllDer
Ihnen gemeint ist.Base
Auch hat nur einx
Mitglied, aber es ist keine eindeutige Basis vonAllDer
. Jede Instanz vonAllDer
hat zwei Unterobjekte vom TypBase
. DaherBase::x
ist in Ihrem Beispiel nicht eindeutig. Und da diesDerived1::Base
nur ein anderer Name istBase
, bleibt dies mehrdeutig.[class.member.lookup] gibt an, dass
x
im Kontext des verschachtelten Namensbezeichners nachgeschlagen wird, sodass dieser zuerst aufgelöst werden muss. Wir suchen in der TatBase::x
nichtDerived1::x
, weil wir damit begonnen haben,Derived1::Base
als zu lösenBase
. Dieser Teil ist erfolgreich.x
InBase.
Anmerkung 12 in [class.member.lookup] wird nur einer explizit darauf hingewiesen, dass die Verwendung einer eindeutigen Namenssuche möglicherweise immer noch fehlschlägt, wenn mehrere Unterobjekte mit demselben Namen vorhanden sind.D::i
In diesem Beispiel ist im Grunde IhreBase::x
.quelle
template <typname A,typename B> struct foo : A,B
mit einem erfundenen Code, um auf Mitglieder einer Basis vonA
und zuzugreifenB
. In diesem Fall möchte ich einen Fehler erhaltenDer Grund, warum Sie den Klassennamen als Mitglied der Klasse bezeichnen können, liegt darin, dass cpp ihn für eine bequeme Verwendung aliasisiert, als ob Sie
using Base = ::Base;
in Base geschrieben hätten.Das Problem, mit dem Sie konfrontiert sind,
Der1::Base
ist dasBase
.Wenn Sie also schreiben
Der1::Base::x
, ist es dasselbe wieBase::x
.quelle
using
ist im Standard geschrieben, und ich denke, das ist der Schlüssel zur Interpretation dessen, was der Ausdruck sagt.cl /c /Wall /WX /Od /MDd /Za /permissive- /std:c++17 main.cpp
als Befehlszeile ichmain.cpp(7): error C2597: illegal reference to non-static member 'A::x'