14

簡単なコードを考えてみましょう:

#include<iostream>

struct A {
    operator double(){
        std::cout<<"Conversion function double chosen."<<std::endl;
        return 1.1;
    }
    operator char(){
        std::cout<<"Conversion function char chosen."<<std::endl;
        return 'a';
    }
} a;

void foo(int){}
void foo (char){}
int main() {
    foo(a);
}

上記のコードは正常に動作し、予想どおりgcc、clang、および VC++foo(char).

コードを少し変更します。

#include<iostream>

struct A {
    operator double(){
        std::cout<<"Conversion function double chosen."<<std::endl;
        return 1.1;
    }
    operator char(){
        std::cout<<"Conversion function char chosen."<<std::endl;
        return 'a';
    }
} a;

void foo(int){}
void foo (double){} //parameter changed from char to double
int main() {
    foo(a);
}

これで choose が必要になりましたが、 clang と gccが上記のコードに満足していないのに対し、 VC++foo(double)だけがこのコードに満足しているようです。

main.cpp:11:10: error: call of overloaded 'foo(A&)' is ambiguous
 foo(a);
     ^
main.cpp:8:6: note: candidate: void foo(int)
 void foo(int){}
      ^
main.cpp:9:6: note: candidate: void foo(double)
 void foo (double){} //parameter changed from char to double
      ^

上記のコードが失敗する理由を誰か説明できますか? それともバグですか?

もう 1 つの質問: gcc と clang はオーバーロード解決のコードを共有していますか?

4

2 に答える 2

5

TL;DR : 違いは、最初のケースでは、2 番目のケースとは対照的に、ユーザー定義の変換シーケンス ( A -> charA -> int) が同じ変換関数 ( operator char) を呼び出すことです。これにより、[over.ics.rank]/(3.3) を介してタイを破ることができます。


特定の関数に最適な変換演算子は、 [over.match.best]/(1.4) (戻り値の型の変換シーケンスの比較) によって選択されます。

したがって、浮動小数点変換が続くのとは対照的に、 のより良い変換関数の後に への昇格foo(int)が続きます。operator charintoperator double

次に、2 番目のオーバーロードの両方のバリアントを考えます。

  1. 最適な ICSfoo(char)経由operator charです(浮動小数点変換よりも ID の方が優れています)。したがって、[over.ics.rank]/(3.3)が適用されます。

    ユーザー定義の変換シーケンスは、同じユーザー定義の変換関数 […] を含む場合、U1別のユーザー定義の変換シーケンスよりも優れた変換シーケンスであり、いずれの場合も、 の 2 番目の標準変換シーケンスはの 2 番目の標準変換シーケンスよりも優れています。U2 U1U2

    したがって、 への全体的な変換F2が優れていると見なされ、選択されます。

  2. 最適な ICSfoo(double)経由operator doubleです。最終的には、異なる変換関数を使用する 2 つの変換シーケンスになります。実際には何も当てはまらず、あいまいさが生じるだけです。

于 2016-03-18T14:04:11.397 に答える