Derived1 :: Base和Derived2 :: Base是否引用相同的类型?


12

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 trough派生类不明确?

PPS:实际上,我的疑问是是Der1::Base指类型,还是类型Base(然后Der2::Base是完全相同的类型)还是子对象。我坚信这是第一个,但是如果是后者,那么MSVC是正确的。



@LanguageLawyer更好地暗示了gcc和clang是正确的,但我并不完全相信mscv是错误的
idclev 463035818

1
显然,两者都引用相同的类型::Base,但是实际的问题在这里似乎略有不同。有两个类型的子对象Base,并且都有一个Base::x 成员。
MSalters

@MSalters PPS仅表示我的困惑。如果您有个更好的标题的建议可以随时编辑,我自己不喜欢(因为我知道答案是肯定的),但是找不到更合适的名称
idclev 463035818

1
@ d4rk4ng31代码中没有虚拟继承(故意)
idclev 463035818

Answers:


6

要回答标题中的问题,可以,请Derived1::Base引用注入的类名 [class.pre] ,引用也是Base如此Derived2::Base。两者都指的是班级::Base

现在,如果Base将具有一个static成员x,则其查找Base::x将是明确的。只有一个。

本示例中的问题在于它x是一个非静态成员,并且AllDer具有两个这样的成员。您可以x通过指定唯一一个成员的明确基类来消除对此类访问的歧义。是一个明确的基类,它有一个成员,因此明确指定您所指的两个成员中的哪个。也只有一个成员,但这并不是的明确基础。的每个实例都有两个类型的子对象。因此在您的示例中是不明确的。而且,由于只是它的别称,所以仍然模棱两可。AllDerxDerived1xDerived1::xxAllDerBasexAllDerAllDerBaseBase::xDerived1::BaseBase

[class.member.lookup]指定x在嵌套名称说明符的上下文中查找的内容,因此必须首先对其进行解析。我们确实在寻找Base::x,不是Derived1::x因为我们从解决Derived1::Baseas 开始Base。这部分成功了,[class.member.lookup] x中的Base.注释12中只有一个明确地告诉您,当存在多个具有相同名称的子对象时,使用明确的名称查找可能仍然会失败。D::i在那个例子中基本上是你的Base::x


所以只有“可能失败”而不是“必须失败”,并且所有三个编译器都是正确的吗?例如template <typname A,typename B> struct foo : A,B,考虑带有一些人为代码的a来访问Aand 的基的成员B。在这种情况下,我想得到一个错误
idclev 463035818

1
@ idclev463035818:我怀疑这是必需的“必须失败” 诊断。特别是,这在7.6.1.4/7类成员访问(格式错误)时失败。
MSalters

我必须多读书。而且我必须对msvc进行一些研究,我怀疑需要某些标志才能获得完全兼容的输出,但必须找出哪些标志
idclev 463035818

2

之所以可以将类名称称为类的成员,是因为cpp为方便使用起了别名,就像您using Base = ::Base;在Base中编写的一样。
您面临的问题Der1::BaseBase
因此,在编写时Der1::Base::x,它与相同Base::x


我知道什么是“问题”,但您没有回答我的问题:“谁是对的?(为什么?)”
idclev 463035818

@ idclev463035818:我相信这是正确的一面。关于的部分using是用标准编写的,我认为这是解释表达式所表示内容的关键。
Dani

@ idclev463035818:看下面的例子。我认为这会清除它。ideone.com/IqpXjT
Dani

对不起,但我认为您不明白我的问题。我想知道什么是正确的标准,因为我看到不同的编译器执行不同的操作。看一个特定的编译器对一个特定的示例做了什么,无助于回答问题
idclev 463035818

仅供参考,MSVC(x64的19.25.28614版)无法在ideone.com/IqpXjT上编译您的示例。使用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'
堆欠载
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.