具有多个函数和多个转换运算符的重载解决方案
Posted
技术标签:
【中文标题】具有多个函数和多个转换运算符的重载解决方案【英文标题】:Overload resolution with multiple functions and multiple conversion operators 【发布时间】:2016-07-04 09:02:33 【问题描述】:考虑简单的代码:
#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共享重载解析的代码吗?
【问题讨论】:
1:定义“不快乐”。 2:如果你删除foo(int)
会发生什么?
@Amit unhappy 表示代码被拒绝,至于删除函数foo(int)
,这不是问题的一部分,您可以自己尝试。
@AngelusMortis:VC++选择哪个函数?
【参考方案1】:
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
都不比另一个好,所以第二种情况是模棱两可的。
【讨论】:
【参考方案2】: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
。我们最终得到两个使用不同转换函数的转换序列;没有什么是真正适用的,我们只是模棱两可。
【讨论】:
以上是关于具有多个函数和多个转换运算符的重载解决方案的主要内容,如果未能解决你的问题,请参考以下文章