MSVC, Clang и GCC не согласны с этим кодом:
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 выдает похожую ошибку, а MSVC не выдает ошибки.
Кто здесь?
Я полагаю, что это описано в [class.member.lookup] , но мне трудно понять, что он пытается сказать мне для этого случая. Пожалуйста, укажите соответствующие части и, если возможно, объясните простым английским языком.
PS: Вдохновлен этим вопросом. Почему ссылка на базовый класс неоднозначна с классом :: -operator через производный класс?
PPS: На самом деле я сомневаюсь, Der1::Base
относится ли это к типу, который будет Base
(а затем Der2::Base
точно такого же типа), или к подобъекту. Я убежден, что это первое, но если оно будет последним, то MSVC будет прав.
c++
language-lawyer
multiple-inheritance
diamond-problem
qualified-name
idclev 463035818
источник
источник
::Base
, но реальный вопрос здесь немного отличается. Есть два подобъекта типаBase
, и оба имеютBase::x
члена.Ответы:
Чтобы ответить на вопрос в заголовке, да,
Derived1::Base
ссылается на имя введенного класса [class.pre]Base
и так жеDerived2::Base
. Оба относятся к классу::Base
.Теперь, если
Base
бы был статический членx
, поискBase::x
был бы однозначным. Здесь только один.Проблема в этом примере заключается в том, что
x
это нестатический член,AllDer
имеющий два таких члена. Вы можете устранить неоднозначность такого доступаx
, указав однозначный базовый класс, вAllDer
который входит только одинx
член.Derived1
является однозначным базовым классом, и он имеет одинx
член, поэтомуDerived1::x
однозначно указывает, какой из двухx
членов вAllDer
вас имеется в виду.Base
тоже имеет только одногоx
члена, но это не однозначная основаAllDer
. Каждый экземплярAllDer
имеет два подобъекта типаBase
. ПоэтомуBase::x
двусмысленно в вашем примере. И посколькуDerived1::Base
это просто другое названиеBase
, это остается неоднозначным.[class.member.lookup] указывает, что поиск производится
x
в контексте спецификатора вложенного имени, поэтому его необходимо решить в первую очередь. Мы действительно ищемBase::x
, а неDerived1::x
потому, что мы начали с решенияDerived1::Base
какBase
. Эта часть выполнена успешно,x
вBase.
примечании 12 в [class.member.lookup] содержится только одно сообщение о том, что использование однозначного поиска имени может все же завершиться неудачей, если существует несколько подобъектов с тем же именем.D::i
в этом примере в основном вашBase::x
.источник
template <typname A,typename B> struct foo : A,B
с некоторым надуманным кодом для доступа к членам базыA
иB
. В таком случае я хочу получить ошибкуПричина, по которой вы можете ссылаться на имя класса как члена класса, заключается в том, что cpp псевдоним его для удобного использования, как если бы вы написали
using Base = ::Base;
внутри Base.Проблема вы столкнулись в том , что
Der1::Base
естьBase
.Таким образом, когда вы пишете
Der1::Base::x
, это так же, какBase::x
.источник
using
написана в стандарте, и я думаю, что это ключ к интерпретации того, что говорит выражение.cl /c /Wall /WX /Od /MDd /Za /permissive- /std:c++17 main.cpp
качестве командной строки, я получаюmain.cpp(7): error C2597: illegal reference to non-static member 'A::x'