考虑简单的代码:
#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是否共享重载解析代码?
答案 0 :(得分:5)
A -> char
是A -> char
。
A -> int
为A -> char -> int
(因为char
至int
为促销,因此优先于double
转换为int
。
A -> double
是A -> double
。
两个用户定义的转换序列只有在涉及相同的用户定义转换函数时才具有可比性。因此,A -> char
是比A -> int
更好的转换序列,因此您的第一个案例是明确的。 A -> int
和A -> double
都不比另一个好,所以第二种情况不明确。
答案 1 :(得分:4)
TL; DR :不同之处在于,在第一种情况下,与第二种情况相反,用户定义的转换序列(A -> char
,A -> int
)调用相同的转换函数(operator char
)。这使我们能够通过[over.ics.rank] /(3.3)打破平局。
[over.match.best]/(1.4)选择特定函数的最佳转换运算符(比较其返回类型的转换序列)。
因此foo(int)
的转换函数为operator char
,然后升级为int
,而operator double
后转换为浮点转换。
现在考虑第二次重载的两种变体:
foo(char)
的最佳ICS 也是operator char
(身份优于浮点转换)。因此[over.ics.rank]/(3.3)适用:
用户定义的转化序列
U1
是一个比其他用户定义的转化序列U2
更好的转换序列,如果它们包含相同的用户定义的转换函数 [...]在任何一种情况下,U1
的第二个标准转换序列都优于U2
的第二个标准转换序列。
因此,整体转换为F2
被视为更好,并且已被选中。
foo(double)
的最佳ICS 来自operator double
。我们最终得到两个采用不同转换函数的转换序列;没有什么真正适用,我们只是含糊不清。