MSVC, Clang e GCC discordam deste código:
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 dá um erro semelhante e MSVC não dá erro.
Quem está bem aqui?
Suponho que isso seja abordado em [class.member.lookup] , mas tenho dificuldades em entender o que está tentando me dizer para esse caso. Por favor, cite as partes relevantes e, se possível, explique em inglês simples.
PS: Inspirado nesta pergunta Por que a referência à classe base é ambígua com :: -operator através da classe derivada?
PPS: Na verdade, minha dúvida é se Der1::Base
refere ao tipo, que seria Base
(e então Der2::Base
é exatamente o mesmo tipo) ou ao subobjeto. Estou convencido de que é o primeiro, mas se for o último, a MSVC estaria certa.
c++
language-lawyer
multiple-inheritance
diamond-problem
qualified-name
idclev 463035818
fonte
fonte
::Base
, mas a verdadeira questão parece ser um pouco diferente aqui. Existem dois subobjetos do tipoBase
e ambos têm umBase::x
membro.Respostas:
Para responder à pergunta no título, sim, faz
Derived1::Base
referência ao nome da classe injetada [class.pre]Base
e o mesmo aconteceDerived2::Base
. Ambos se referem à classe::Base
.Agora, se
Base
tivesse um membro estáticox
, a pesquisa deBase::x
seria inequívoca. Existe apenas um.O problema neste exemplo é que
x
é um membro não estático eAllDer
possui dois desses membros. Você pode desambiguar esse acessox
especificando uma classe base inequívoca daAllDer
qual possui apenas umx
membro.Derived1
é uma classe base inequívoca e tem umx
membro, portanto,Derived1::x
sem ambiguidade, especifica qual dos doisx
membrosAllDer
você quer dizer.Base
também tem apenas umx
membro, mas não é uma base inequívoca deAllDer
. Cada instânciaAllDer
tem dois sub-objetos do tipoBase
. Portanto,Base::x
é ambíguo no seu exemplo. E como esseDerived1::Base
é apenas outro nomeBase
, isso permanece ambíguo.[class.member.lookup] especifica que
x
é procurado no contexto do especificador de nome aninhado, para que seja resolvido primeiro. Na verdade, estamos procurandoBase::x
, nãoDerived1::x
, porque começamos resolvendoDerived1::Base
comoBase
. Esta parte é bem-sucedida, há apenas umax
naBase.
Nota 12 em [class.member.lookup] explicitamente que o uso de uma pesquisa de nome inequívoca ainda pode falhar quando há vários subobjetos com o mesmo nome.D::i
nesse exemplo é basicamente o seuBase::x
.fonte
template <typname A,typename B> struct foo : A,B
com algum código artificial para acessar membros de uma base deA
eB
. Nesse caso, eu quero obter um erroO motivo pelo qual você pode se referir ao nome da classe como um membro da classe é porque o cpp o alia para uso conveniente, como se você tivesse escrito
using Base = ::Base;
dentro do Base.O problema que você está enfrentando é que
Der1::Base
éBase
.Assim, quando você escreve
Der1::Base::x
, é o mesmo queBase::x
.fonte
using
está escrita no padrão, e acho que é a chave para interpretar o que a expressão diz.cl /c /Wall /WX /Od /MDd /Za /permissive- /std:c++17 main.cpp
como linha de comando, eu recebomain.cpp(7): error C2597: illegal reference to non-static member 'A::x'