算术运算符的规则实际上与一般函数重载决议的规则略有不同。
来自算术运算符的 cppreference :
转换
如果传递给算术运算符的操作数是整数或无作用域枚举类型,则在任何其他操作之前(但在左值到右值转换之后,如果适用),操作数会经历整数提升。如果操作数具有数组或函数类型,则应用数组到指针和函数到指针的转换。
对于二元运算符(移位除外),如果提升的操作数具有不同的类型,则应用附加的隐式转换集,称为通常的算术转换,其目标是生成通用类型(也可通过std::common_type
类型特征访问)。如果在任何整数提升之前,一个操作数是枚举类型,而另一个操作数是浮点类型或不同的枚举类型,则不推荐使用此行为。(C++20 起)
- 如果任一操作数具有范围枚举类型,则不执行转换:另一个操作数和返回类型必须具有相同的类型
- 否则,如果任一操作数为
long double
,则将另一个操作数转换为long double
- 否则,如果任一操作数为
double
,则将另一个操作数转换为double
- 否则,如果任一操作数为
float
,则将另一个操作数转换为float
[剪辑]
因此,非常明确地,当我们执行 时unsigned + float
,unsigned
将转换为float
. 这是适用的第一条规则,所以我们遵循它。
但是,对于一般的重载决议,从unsigned
tofloat
的转换等同于从 to 的float
转换unsigned
。因此,例如在以下代码片段中:
unsigned add(unsigned l, unsigned r) { return l + r; }
float add(float l, float r) { return l + r; }
int main()
{
unsigned ui = 1;
float fval = 2.5;
add(ui, fval);
}
它无法决定add
使用哪个版本并且无法编译。