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

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]에 포함되어 있다고 생각 하지만,이 사건에 대해 무엇을 말하려고하는지 이해하는 데 어려움이 있습니다. 관련 부분을 인용하고 가능한 경우 일반 영어로 설명하십시오.

추신 :이 질문에서 영감을 얻은 이유 :: :: 연산자 trough 파생 클래스에서 기본 클래스에 대한 참조가 모호한 이유는 무엇입니까?

PPS : 실제로 내 의심은 Der1::Base유형을 나타내는 지, Base그리고 Der2::Base정확히 동일한 유형인지 또는 하위 객체를 나타내는 지 여부입니다. 나는 그것이 첫 번째라고 확신하지만, 후자라면 MSVC가 옳을 것입니다.



@LanguageLawyer gcc와 clang이 옳다는 더 좋은 힌트가 있지만 mscv가 잘못되었다는 것을 완전히 확신
하지는 못합니다

1
분명히 둘 다 같은 유형을 참조 ::Base하지만 실제 질문은 여기에서 약간 다르게 보입니다. 유형의 하위 오브젝트는 두 가지 Base이며 둘 다 Base::x 멤버를 갖습니다 .
MSalters

@MS는 PPS를 단순히 내 혼란을 표현합니다. 무료 편집에 더 나은 제목의 느낌에 대한 제안이 있다면, 나는 (내가 대답은 '예'입니다 알고 있기 때문에)이 자신을 좋아하지 않아,하지만 더 적절한 것을 찾지 못했습니다
idclev 463,035,818

1
@ d4rk4ng31 코드에 가상 상속이 없습니다 (의도적)
idclev 463035818

답변:


6

제목에 질문에 대답하기 위해, 예, Derived1::Base참조합니다 주입-클래스 이름 [class.pre] Base 지금과는 않습니다 Derived2::Base. 둘 다 클래스를 참조하십시오 ::Base.

이제 정적 멤버 Base가 있으면 조회 가 명확합니다. 하나만 있습니다.xBase::x

이 예에서의 문제점은이 x비 고정 부재이며 AllDer갖는 이러한 부재. 멤버 가 하나만 x있는 모호하지 않은 기본 클래스를 지정하여 이러한 액세스를 명확하게 할 수 있습니다 . 모호하지 않은 기본 클래스이며 멤버 가 하나 이므로 두 멤버 중 의미하는 것을 명확하게 지정합니다 . 멤버 도 하나 뿐이지 만의 모호한 기초는 아닙니다 . 의 모든 인스턴스 에는 유형의 하위 객체가 두 개 있습니다. 따라서 귀하의 예에서는 모호합니다. 그리고 또 다른 이름 이기 때문에AllDerxDerived1xDerived1::xxAllDerBasexAllDerAllDerBaseBase::xDerived1::BaseBase 모호합니다.

[class.member.lookup] x은 nested-name-specifier의 컨텍스트에서 조회되도록 지정하므로 먼저 해결해야합니다. 우리는 참으로 찾고 있습니다 Base::x하지, Derived1::x우리가 해결하여 시작했기 때문에, Derived1::BaseBase. 이 부분은 단 하나있다, 성공 xBase.주 (12)가 명시 적으로 명확한 이름 조회를 사용하여 아직도 그 같은 이름을 가진 여러 하위 객체가있을 때 실패 할 수 있음을 알려줍니다 [class.member.lookup]에. D::i이 예에서 기본적으로 당신 Base::x입니다.


"실패"할 수는 있지만 "실패해야"하지 않으며 세 컴파일러 모두 맞습니까? 예를 들어 A에 대한 고려 template <typname A,typename B> struct foo : A,B(A)의 기본의 액세스 회원들에게 어떤 인위적인 코드 AB. 이 경우 오류가 발생합니다
idclev 463035818

1
@ idclev463035818 : " 필수 " 진단이 필요한 것 같습니다 . 특히, 7.6.1.4/7 클래스 멤버 액세스에서 "잘못된 형식"에 실패합니다.
MSalters

좀 더 읽어야합니다. 그리고 msvc에 대한 연구를해야합니다. 일부 플래그는 완전히 호환되는 출력을 얻기 위해 필요하지만 어떤 플래그를 찾아야
한다고 생각

2

클래스 이름을 클래스의 멤버로 참조 할 수있는 이유는 cpp using Base = ::Base;가 Base에 작성한 것처럼 편리하게 사용할 수 있도록 cpp의 별칭을 지정하기 때문 입니다.
직면 한 문제 Der1::BaseBase입니다.
따라서 쓸 때 Der1::Base::x와 동일합니다 Base::x.


"문제"가 무엇인지 알고 있지만 "내가 옳은 이유는 무엇입니까?"
idclev 463035818

@ idclev463035818 : 이것이 옳다고 생각합니다. 에 관한 부분은 using표준으로 작성되었으며, 이것이 표현이 말하는 것을 해석하는 열쇠라고 생각합니다.
Dani

@ idclev463035818 : 다음 예를보십시오. 나는 그것을 조금 정리할 것이라고 생각합니다. ideone.com/IqpXjT
Dani

미안하지만 내 질문의 요점을 알 수 없다고 생각합니다. 다른 컴파일러가 다른 일을하는 것을 보았 기 때문에 표준에 따라 올바른 것이 무엇인지 알고 싶습니다. 하나의 특별한 컴파일러는 하나의 특정 예에 무엇을 살펴보면, 질문에 대답하는 데 도움이되지 않습니다
idclev 463,035,818을

참고로 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'
힙 언더런이 발생합니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.