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:この質問に触発されましたなぜベースクラスへの参照が::-演算子トラフ派生クラスで曖昧なのですか?

PPS:実際、私の疑問はDer1::Base、型を参照するのか、それともその型を参照するのかBase(それからDer2::Baseまったく同じ型になるのか)、またはサブオブジェクトを参照するのかです。私はそれが最初のものであると確信していますが、もしそれが後者であるならば、MSVCは正しいでしょう。



@LanguageLawyer gccとclangが正しいというより良いヒントですが、mscvが間違っていると私は完全には確信していません
idclev 463035818

1
明らかに両方とも同じタイプを参照して::Baseいますが、実際の質問はここでは少し異なります。タイプの2つのサブオブジェクトがありBase、どちらにもBase::x メンバーがあります。
MSalters

@MSalters PPSは単に私の混乱を表しています。より良いタイトルの提案がありましたら、自由に編集してください(私は答えが「はい」であることを知っているので)私はそれが好きではありませんが、より適切なものを見つけませんでした
idclev 463035818

1
@ d4rk4ng31コードには仮想継承がありません(意図的)
idclev 463035818

回答:


6

タイトルの質問に答えるために、はい、注入されたクラス名 [class.pre]Derived1::Base参照します。どちらもクラスを参照します。 BaseDerived2::Base::Base

これでBase静的メンバーxがある場合、のルックアップはBase::x明確になります。ただ一つしかない。

この例の問題は、それxが非静的メンバーであり、そのようなメンバーAllDer2つあることです。メンバーが1つしかない明確な基本クラスをx指定することにより、このようなアクセスを明確にすることができます。は明確な基本クラスであり、1つのメンバーがあるため、2つのメンバーのどちらを意味するかを明確に指定します。にもメンバーは1つしかありませんが、の明確なベースではありません。のすべてのインスタンスには、タイプの2つのサブオブジェクトがあります。したがって、例ではあいまいです。はの別名にすぎないため、あいまいなままです。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です。


それで、「失敗するかもしれない」だけで「失敗する必要がある」わけではなく、3つのコンパイラすべてが正しいのでしょうか。例えばAの検討template <typname A,typename B> struct foo : A,Bのベースのアクセスメンバーに何らかの工夫コードでAB。そのような場合、エラーが発生します
idclev 463035818

1
@ idclev463035818:「失敗しなければならない」診断が必要だと思い ます。特に、これは7.6.1.4/7クラスメンバーアクセス、「不正な形式」では失敗します。
MSalters

私はもう少し読む必要があります。そして、私はMSVCのいくつかの研究を行う必要があり、私はいくつかのフラグは完全に準拠した出力を得るために必要とされていることを疑うが、その旗を見つけなければならない
idclev 463035818

2

クラスのメンバーとしてクラス名を参照できるのは、cpp using Base = ::Base;がBaseの中で書いたかのように、使いやすいようにエイリアスを付けているからです。
あなたが直面している問題はそれDer1::BaseですBase
したがって、を書くとDer1::Base::x、と同じになりBase::xます。


「問題」は何なのかはわかっていますが、私の質問には答えていません。「だれが正しいのですか(そしてなぜですか)」
idclev 463035818

@ idclev463035818:これは右側だと思います。約部分usingは標準で書かれていて、それが表現が言うことを解釈するための鍵だと思います。
ダニ

@ idclev463035818:次の例を見てください。少し晴れると思います。ideone.com/IqpXjT
ダニ

申し訳ありませんが、私の質問の要点は理解できません。コンパイラーによって処理が異なるので、標準に従って何が正しいのか知りたいのですが。特定のコンパイラが特定の例に対して何をするのかを見ても、質問に答えるのに役立ちません
idclev 463035818

ちょうどFYI、(x64のための19.25.28614版)MSVCはであなたの例をコンパイルに失敗し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.