web-dev-qa-db-ja.com

ダイヤモンド問題を解決するために使用宣言が機能しないのはなぜですか?

次のコードを検討してください。

struct A
{
    void f()
    {
    }
};

struct B1 : A
{
};

struct B2 : A
{
};

struct C : B1, B2
{
    void f() // works
    {
        B1::f();
    }
    //using B1::f; // does not work
    //using B1::A::f; // does not work as well
};

int main()
{
    C c;
    c.f();

    return 0;
}

菱形継承問題を解決する方法(「仮想継承を使用する」)に関する標準的な返信をコピーして貼り付けないでください。ここで私が求めているのは、この場合、なぜusing宣言が機能しないのかということです。正確なコンパイラエラーは次のとおりです。

In function 'int main()':
prog.cpp:31:6: error: 'A' is an ambiguous base of 'C'
  c.f();

この例から、using宣言が機能するはずだという印象を受けました。

struct A
{
    void f()
    {
    }
};

struct B
{
    void f()
    {
    }
};

struct C : A, B
{
    using A::f;
};

int main()
{
    C c;
    c.f(); // will call A::f

    return 0;
}
52
gd1

[namespace.udecl]/p17には、この状況に直接対処するメモがあります。

[sing-declarationは基本クラスのメンバー(メンバーサブオブジェクトまたは基本クラスサブオブジェクトのメンバー関数ではない)を指定するため、sing -declaration継承されたメンバーのあいまいさを解決するために使用することはできません。例えば、

struct A { int x(); };
struct B : A { };
struct C : A {
    using A::x;
    int x(int);
};
struct D : B, C {
    using C::x;
    int x(double);
};
int f(D* d) {    
    return d->x(); // ambiguous: B::x or C::x
}

文末脚注]

28
T.C.

T.C.の回答に加えて、派生クラスでの名前ルックアップは、セクション10.2で標準でかなり詳細に説明されていることを付け加えたいと思います。

ここで、using宣言の処理について何が言われていますか:

10.2/3:ルックアップセット(...)は、2つのコンポーネントセットで構成されています。宣言セット、fという名前のメンバーのセット。サブオブジェクトセットは、これらのメンバーの宣言(おそらくusing-declarationsを含む)が見つかったサブオブジェクトのセットです。宣言セットでは、sing-declarationsが置き換えられます指定されたメンバーに置き換えられ、型宣言(注入されたクラス名を含む)が指定された型に置き換えられます。

したがって、struct Cで宣言しようとすると

using B1::f; // you hope to make clear that B1::f is to be used

それでも、ルックアップルールに従って、コンパイラは可能な候補を見つけます:B1::fおよびB2::fなので、まだあいまいです。

5
Christophe