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

问题描述 投票:12回答:2

[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;
    }
};

Godbolt

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:受此问题启发Why is Reference to Base Class ambiguous with :: -operator trough derived class?

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

c++ language-lawyer multiple-inheritance diamond-problem qualified-name
2个回答
6
投票

要回答标题中的问题,是的,Derived1::Base引用了injected-class-name [class.pre] BaseDerived2::Base也引用了。两者都引用类::Base

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

此示例中的问题是x是非静态成员,并且AllDer具有two这样的成员。您可以通过指定只有一个x成员的AllDerunambiguous基类来消除对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.。[class.member.lookup]中的注释12明确告诉您,当存在多个具有相同名称的子对象时,使用明确的名称查找可能仍然会失败。在该示例中,D::i基本上就是您的Base::x


2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.