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);
}

现在这应该有选择foo(double),但似乎只有VC++对代码感到满意,而clang 和 gcc对上述代码不满意。

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
      ^

谁能解释为什么上面的代码失败了?还是它的错误?

还有一个问题:gcc 和 clang 是否共享重载解析代码?

4

2 回答 2

6

A -> charA -> char

A -> intA -> char -> int(因为chartoint是一种提升,因此胜过doubletoint转换)。

A -> doubleA -> double

Two user-defined conversion sequences are only comparable if they involve the same user-defined conversion function. Thus, A -> char is a better conversion sequence than A -> int, so your first case is unambiguous. Neither A -> int nor A -> double is better than the other, so the second case is ambiguous.

于 2016-03-17T22:57:54.280 回答
5

TL;DR: The difference is that in the first case, as opposed to the second, the user-defined conversion sequences (A -> char, A -> int) call the same conversion function (operator char). That enables us to break the tie via [over.ics.rank]/(3.3).


The best conversion operators for particular functions are selected by [over.match.best]/(1.4) (comparing the conversion sequences of their return types).

Hence the better conversion function for foo(int) is operator char followed by a promotion to int, as opposed to operator double followed by a floating point conversion.

Now consider both variants of the second overload:

  1. The best ICS to foo(char) is also via operator char (identity better than floating point conversion). Thus [over.ics.rank]/(3.3) is applicable:

    User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if they contain the same user-defined conversion function […] and in either case the second standard conversion sequence of U1 is better than the second standard conversion sequence of U2.

    Hence the overall conversion to F2 is deemed better, and it is selected.

  2. The best ICS to foo(double) is via operator double. We end up with two conversion sequences employing distinct conversion functions; nothing really applies, and we just get an ambiguity.

于 2016-03-18T14:04:11.397 回答