当你有x + i
, since x
是类类型,重载解析开始:
标准中的具体细节([over.match.oper]p2)
如果任一操作数的类型为类或枚举,则可能会声明实现此运算符的用户定义的运算符函数,或者可能需要用户定义的转换才能将操作数转换为适合内置类型的类型。在运算符中。
在这种情况下,重载决策用于确定要调用哪个运算符函数或内置运算符来实现该运算符。
内置候选者在第 3.3 段中定义:
For the operator ,
, 一元operator &
, 或者operator ->
,内置候选集为空。对于所有其他运算符,内置候选运算符包括 [over.built] 中定义的所有候选运算符函数,与给定运算符相比,
- 具有相同的操作员名称,并且
- 接受相同数量的操作数,并且
- 接受给定操作数可以根据 [over.best.ics] 转换为的操作数类型,以及
- 不具有与非函数模板特化的任何非成员候选者相同的参数类型列表。
根据 [over.built]p13,内置候选函数可以包括:
对于每对类型 L 和 R,其中 L 和 R 都是浮点型或提升整型,存在以下形式的候选运算符函数
LR operator*(L, R);
...
LR operator+(L, R);
...
bool operator>=(L, R);
其中 LR 是类型 L 和 R 之间常见算术转换 ([expr.arith.conv]) 的结果。
所以有一个内置函数int operator+(int, int)
.
至于可能的隐式转换序列有哪些:
[over.best.ics]p3:
格式良好的隐式转换序列是以下形式之一:
- 标准转换序列,
- 用户定义的转换序列,或
- 省略号转换序列。
这里使用了用户定义的转换序列,由 [over.ics.user] 定义:
用户定义的转换序列由初始标准转换序列、用户定义的转换 ([class.conv]) 和第二个标准转换序列组成。
(这里,两个标准转换序列都是空的,并且您的用户定义的转换为int
可以使用)
所以当检查是否int operator+(int, int)
是一个内置候选者,这是因为您的类类型和int
.
至于实际的重载解析,来自[over.match.oper]:
- 某些运算符@的重载决策的候选函数集是该运算符@的成员候选者、非成员候选者、内置候选者和重写候选者的并集。
- 参数列表包含运算符的所有操作数。
根据[over.match.viable]和[over.match.best]从候选函数集中选择最佳函数。
And int operator+(int, int)
显然是最好的匹配,因为它不需要第二个参数的转换,只需要用户定义的第一个参数的转换,所以它击败了其他候选者,例如long operator+(long, int)
and long operator+(int, long)
你可以看到内置候选集为空的问题,因为GCC错误报告有no可行的候选人。如果你有:
auto add(int a, int b) -> int
{
return a + b;
}
auto main() -> int
{
auto i = int{0};
auto x = Wrapper<int>(i);
return add(x, i);
}
现在它可以很好地与 GCC 编译,因为::add(int, int)
被认为是候选者,即使它应该与内置运算符没有什么不同int operator+(int, int)
.
如果你有:
template<class S = T>
operator S() { return _value; } // Can convert to any type
Clang 现在出现错误:
<source>:16:14: error: use of overloaded operator '+' is ambiguous (with operand types 'Wrapper<int>' and 'int')
return x + i;
~ ^ ~
<source>:16:14: note: built-in candidate operator+(float, int)
<source>:16:14: note: built-in candidate operator+(double, int)
<source>:16:14: note: built-in candidate operator+(long double, int)
<source>:16:14: note: built-in candidate operator+(__float128, int)
<source>:16:14: note: built-in candidate operator+(int, int)
<source>:16:14: note: built-in candidate operator+(long, int)
<source>:16:14: note: built-in candidate operator+(long long, int)
<source>:16:14: note: built-in candidate operator+(__int128, int)
<source>:16:14: note: built-in candidate operator+(unsigned int, int)
<source>:16:14: note: built-in candidate operator+(unsigned long, int)
<source>:16:14: note: built-in candidate operator+(unsigned long long, int)
<source>:16:14: note: built-in candidate operator+(unsigned __int128, int)
(请注意,此错误消息不包括第二个参数的转换,但由于永远不会选择这些转换,因此它们可能不被视为优化)
GCC 仍然表示根本没有候选者,尽管所有这些内置候选者都存在。