12

重複の可能性:
同じ名前で異なるシグネチャを持つ複数の継承された関数がオーバーロードされた関数として扱われないのはなぜですか?

これは、g++4.6.1で指定された場所でコンパイルできません。

enum Ea { Ea0 };
enum Eb { Eb0 };

struct Sa { void operator()(Ea) {} };
struct Sb { void operator()(Eb) {} };
struct Sbroken : Sa, Sb {};

struct Sworks {
    void operator()(Ea) {}
    void operator()(Eb) {}
};

int main() {
    Sworks()(Ea0);
    Sbroken()(Ea0); // g++ can't disambiguate Ea vs. Eb
}

Clang 2.8はこのコードをコンパイルするため、コードが本当に有効なC++であるかどうかがわかりません。私はclangが正しく、g ++が間違っていると楽観的に結論付けようとしていましたが、小さな変更を加えたため、clangにも同様のエラーが発生しました。

enum Ea { Ea0 };
enum Eb { Eb0 };

struct Sa { void f(Ea) {} };
struct Sb { void f(Eb) {} };
struct Sbroken : Sa, Sb {};

struct Sworks {
    void f(Ea) {}
    void f(Eb) {}
};

int main() {
    Sworks().f(Ea0);
    Sbroken().f(Ea0); // both clang and g++ say this is ambiguous
}

そこで行った唯一の変更は、fではなく名前付き関数を使用することでしたoperator()。なぜこれが重要なのかわかりませんが、重要です。このバージョンはg++でもclangでもコンパイルされません。

4

2 に答える 2

5

基本クラスで関数を非表示にすることと関係があると思います。GCCのエラーメッセージは、次structの代わりに使用してもあまり役に立たないようですenum。実際、エラーメッセージは誤解を招く可能性があります。EaEbは2つの異なるクラスであり、からへの暗黙の変換がないため、あいまいさは発生しないはずですが、GCCは私に同意しないようです:http://ideone.com/cvzLW (変更も参照)。EaEb

とにかく、関数をクラススコープに入れる場合は、次のように明示的に記述usingします。

struct Sbroken : Sa, Sb 
{
   using Sa::operator();
   using Sb::operator();
};

その後、動作します:http: //ideone.com/LBZgC

他の例でも同じです:

struct Sbroken : Sa, Sb 
{
   using Sa::f;
   using Sb::f;
};

コード: http: //ideone.com/3hojd

于 2011-11-10T17:38:26.977 に答える
4

標準(§10.2)の実際のテキストを理解しようとするのは簡単ではありませんが、それを明確にする例があります。x 派生クラスに名前が存在しない場合、派生クラスの名前の名前検索は失敗します。ただし、複数の基本クラスに存在し、非表示にはなりません。(非表示は、仮想継承が存在する場合にのみ介入するため、ここでは関係ありません。)私が知る限り、これはメンバーの名前に関係なく当てはまります。メンバーがたまたま特別な名前を持っていても例外はありませんoperator()。オーバーロードセットが完全に構築される前に、名前ルックアップで失敗するため、オーバーロード解決は機能しません。両方のコードスニペットが違法であり、clangにバグがあることは間違いありません。

宣言を使用usingして名前を派生クラスに挿入するか、派生クラスで転送演算子を明示的に定義できます。派生クラスで名前が見つかると、コンパイラは停止し、基本クラスを検索しません。

于 2011-11-10T17:57:23.407 に答える