MSVC, Clang y GCC no están de acuerdo con este 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;
}
};
CCG:
<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 da un error similar y MSVC no da ningún error.
¿Quién está aquí?
Supongo que esto está cubierto en [class.member.lookup] , pero tengo dificultades para entender lo que está tratando de decirme para este caso. Por favor, cite las partes relevantes y, si es posible, explique en inglés simple
PD: Inspirado por esta pregunta ¿Por qué la referencia a la clase base es ambigua con :: -operator a través de la clase derivada?
PPS: En realidad, mi duda es si se Der1::Base
refiere al tipo, que sería Base
(y luego Der2::Base
es exactamente el mismo tipo), o al subobjeto. Estoy convencido de que es el primero, pero si es el último, entonces MSVC estaría en lo cierto.
c++
language-lawyer
multiple-inheritance
diamond-problem
qualified-name
idclev 463035818
fuente
fuente
::Base
, pero la pregunta real parece ser ligeramente diferente aquí. Hay dos subobjetos de tipoBase
, y ambos tienen unBase::x
miembro.Respuestas:
Para responder la pregunta en el título, sí, hace
Derived1::Base
referencia al nombre de la clase inyectada [class.pre]Base
y también lo haceDerived2::Base
. Ambos se refieren a la clase.::Base
.Ahora, si
Base
tuviera un miembro estáticox
, entonces la búsqueda deBase::x
sería inequívoca. Sólo hay uno.El problema en este ejemplo es que
x
es un miembro no estático yAllDer
tiene dos de esos miembros. Puede desambiguar dicho accesox
especificando una clase base inequívoca de laAllDer
cual solo tiene unx
miembro.Derived1
es una clase base inequívoca y tiene unx
miembro, por loDerived1::x
que especifica inequívocamente a cuál de los dosx
miembrosAllDer
se refiere.Base
también tiene un solox
miembro, pero no es una base inequívoca deAllDer
. Cada instancia deAllDer
tiene dos subobjetos de tipoBase
. PorBase::x
lo tanto, es ambiguo en su ejemplo. Y dado queDerived1::Base
es solo otro nombre paraBase
, esto sigue siendo ambiguo.[class.member.lookup] especifica que
x
se busca en el contexto del especificador de nombre anidado, por lo que debe resolverse primero. De hecho, estamos buscandoBase::x
, noDerived1::x
, porque comenzamos resolviendoDerived1::Base
comoBase
. Esta parte tiene éxito, solo hay unax
en laBase.
Nota 12 en [class.member.lookup] que le dice explícitamente que el uso de una búsqueda de nombres inequívoca aún puede fallar cuando hay múltiples subobjetos con ese mismo nombre.D::i
en ese ejemplo es básicamente tuBase::x
.fuente
template <typname A,typename B> struct foo : A,B
código inventado para acceder a miembros de una base deA
yB
. En tal caso, quiero obtener un errorLa razón por la que puede referirse al nombre de la clase como miembro de la clase es porque cpp lo alias para un uso conveniente, como si escribiera
using Base = ::Base;
dentro de Base.El problema que enfrenta es que
Der1::Base
esBase
.Por lo tanto, cuando escribes
Der1::Base::x
, es lo mismo queBase::x
.fuente
using
está escrita en el estándar, y creo que esa es la clave para interpretar lo que dice la expresión.cl /c /Wall /WX /Od /MDd /Za /permissive- /std:c++17 main.cpp
como línea de comando, obtengomain.cpp(7): error C2597: illegal reference to non-static member 'A::x'