对于以下表达式:-
int main()
{
unsigned ui = 1;
float fval = 2.5;
cout << sizeof(ui) << endl << sizeof(fval) << endl;
cout << typeid(ui+fval).name();
}
我们得到以下输出:-
4
4
f
ui+fval似乎是一个浮点数。
然而,考虑到float和unsigned int都是4字节,并且不是所有的unsigned int值都可以放在float中,那么fval不应该转换为unsigned int吗?
算术运算符的规则实际上与一般函数重载解析的规则略有不同。
来自算术运算符的cppreference:
转换
如果传递给算术运算符的操作数是整型或无作用域枚举类型,则在任何其他操作之前(但在左值到右值转换之后,如果适用),操作数进行整型提升。如果操作数是数组或函数类型,则应用数组到指针和函数到指针的转换。
对于二元操作符(移位除外),如果提升的操作数具有不同的类型,则应用额外的隐式转换集,称为常规算术转换,目的是产生公共类型(也可通过
std::common_type
类型特征访问)。如果在任何整型提升之前,一个操作数是枚举类型,而另一个操作数是浮点类型或不同的枚举类型,则不赞成这种行为。(因为C + + 20)
- 如果其中一个操作数具有作用域枚举类型,则不执行转换:另一个操作数和返回类型必须具有相同的类型
- 如果其中一个操作数为
long double
,则另一个操作数转换为long double
- 否则,如果其中一个操作数为
double
,则另一个操作数转换为double
- 否则,如果其中一个操作数为
(剪)float
,则另一个操作数转换为float
所以,很明显,当我们做unsigned + float
时,unsigned
被转换成float
。这是第一条适用的规则,所以我们遵循它。
但是,对于一般的过载解析,从unsigned
到float
的转换相当于从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
,编译失败。