1

次のオーバーロードされた関数呼び出しがあいまいなのはなぜですか?? コンパイルエラーで:

オーバーロードされた 'test(long int)' の呼び出しがあいまいです。候補は次のとおりです: void test(A)| ボイドテスト(B)|

コード:

class A
{
    public:
        A(int){}
        A(){}
};

class B: public A
{
    public:
        B(long){}
        B(){}
};

void test(A a)
{
}

void test(B b)
{
}

void main()
{
    test(0L);
    return;
}
4

5 に答える 5

6

オーバーロードの解決では、2 つの同等に実行可能な関数 (両方ともユーザー定義の変換がある) から選択する必要があるため、エラーが発生しました。関数オーバーロードの解決は非常に複雑な問題です。過負荷解決の詳細については、Stephan T. Lavavej による最近の講義などを参照してください。通常、単一引数のコンストラクターを作成explicitしてから、明示的なコンストラクター引数を使用して関数を呼び出すのが最善です。

test(0L)オーバーロードがないため、オーバーロードと完全に一致しませんtest(long)。あなたが提供した 2 つのオーバーロードはどちらも、引数にユーザー定義の変換がありますが、コンパイラはそれらを同等に実行可能と見なします。オーバーAロードでは、標準の変換 (long から int へ) の後にユーザー定義の変換 (int から A へ) を実行し、Bオーバーロードではユーザー定義の変換 (long から B へ) を実行する必要があります。ただし、どちらもユーザー定義の暗黙的な変換シーケンスです。

これらはどのようにランク付けされていますか?標準では、13.3.3.2 ランキングの暗黙的な変換シーケンス [over.ics.rank]で述べられています。

S1 が S2 の適切なサブシーケンスである場合、標準変換シーケンス S1 は標準変換シーケンス S2 よりも優れた変換シーケンスです。

これらのタイプのタイブレークは、たとえば、A が B から派生したクラスである場合 (またはその逆) に適用されます。しかし、ここではどちらの変換シーケンスも他方のサブシーケンスではありません。したがって、それらは等しく実行可能であり、コンパイラは呼び出しを解決できません。

class A
{
public:
    explicit A(int){}
    A(){}
};

class B: public A
{
public:
    explicit B(long){}
    B(){}
};

void test(A a)
{}

void test(B b)
{}

int main()
{
    test(A(0L));  // call first overload
    test(B(0L)); // call second overload
    return 0;
}

注:int main()ではなく、void main()です。

于 2012-08-09T09:47:20.480 に答える
1

long 型のパラメーターを使用して test を呼び出しています。

テスト(長い)はありません。

コンパイラは、test(A) と test(B) のどちらかを選択する必要があります。

test(A) を呼び出すには、long -> int -> A の変換シーケンスがあります。

test(B) を呼び出すには、long -> B の変換シーケンスがあります。

標準のランキング規則に応じて、一方が他方よりもランク付けされている場合に 1 つを選択するか、あいまいさで失敗します。

この特定のケースでは、2 つの変換シーケンスが同等にランク付けされます。

セクション13.3.3 実行可能な最良の関数で変換シーケンスのランキングを計算する方法について、標準の規則の長いリストがあります。

于 2012-08-09T09:54:28.953 に答える
1

関数のオーバーロードでは、正確な引数の型または暗黙的な変換が考慮されます。あなたの例では、暗黙のコンストラクター呼び出しが必要なため、オーバーロードの観点からは両方の選択肢 A(0L) と B(0L) は同じです。

于 2012-08-09T09:49:20.883 に答える
0

コンパイラは、ユーザー型への暗黙的な変換を 1 回だけ行うことができます。これにプリミティブ型間の変換も含まれる場合、それらはカウントされません。2 つの変換が行われている場合でもtest(B)、次のコードはコンパイルされません。

class B
{
public:
    B(int) {}
};

class A
{
public:
    A(const B&) {}
};

void test(const A&) {}

....

test(5);

暗黙的な変換を行うコンパイラを無効にするにはexplicit、コンストラクタでキーワードを使用する必要があります

于 2012-08-09T10:07:36.063 に答える
0

これを試して:

class A
{
  public:
  explicit A(int){}
  A(){}
};

キーワード explicit は、コンパイラによる暗黙的な変換を停止します。

于 2012-08-09T09:47:42.290 に答える