Do Derived1::Base and Derived2::Base refer to the same type?

本小妞迷上赌 提交于 2020-05-12 11:38:01

问题


MSVC, Clang and GCC disagree on this code:

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 gives a similar error, and MSVC gives no error.

Who is right here?

I suppose this is covered in [class.member.lookup], but I have difficulties understanding what it is trying to tell me for this case. Please quote the relevant parts and if possible explain in plain English.

PS: Inspired by this question Why is Reference to Base Class ambiguous with :: -operator trough derived class?

PPS: Actually my doubt is whether Der1::Base refers to the type, that would be Base (and then Der2::Base is exactly the same type), or to the subobject. I am convinced that it is the first, but if it is the latter then MSVC would be right.


回答1:


To answer the question in the title, yes, Derived1::Base references the injected-class-name [class.pre] Base and so does Derived2::Base. Both refer to the class ::Base.

Now, if Base would have a static member x, then the lookup of Base::x would be unambiguous. There's only one.

The problem in this example is that x is a non-static member, and AllDer has two such members. You can disambiguate such access to x by specifying an unambiguous base class of AllDer which has only one x member. Derived1 is an unambiguous base class, and it has one x member, so Derived1::x unambiguously specifies which of the two x members in AllDer you mean. Base too has only one x member, but it is not an unambiguous base of AllDer. Every instance of AllDer has two sub-objects of type Base. Therefore Base::x is ambiguous in your example. And since Derived1::Base is just another name for Base, this remains ambiguous.

[class.member.lookup] specifies that x is looked up in the context of the nested-name-specifier, so that has to be resolved first. We are indeed looking for Base::x, not Derived1::x, because we started by resolving Derived1::Base as Base. This part succeeds, there's only one x in Base. Note 12 in [class.member.lookup] explicitly tells you that an using an unambiguous name lookup may still fail when there are multiple subobjects with that same name. D::i in that example is basically your Base::x.




回答2:


The reason you can refer to the class name as a member of the class is because cpp aliases it for convenient use, as if you wrote using Base = ::Base; inside Base.
The problem you’re facing is that Der1::Base is Base.
Thus, when you write Der1::Base::x, it’s the same as Base::x.



来源:https://stackoverflow.com/questions/61477009/do-derived1base-and-derived2base-refer-to-the-same-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!