一般算术转换
来自cppreference.com
许多期待具有算术类型或枚举类型的操作数的二元运算符会以相似的方法进行转换并产生结果类型。这样做的目的是产生公共类型,也就是结果类型。该模式被称为一般算术转换。
定义
一般算数转换定义如下:
阶段 1
对两个操作数进行左值到右值转换,在后续过程中将转换结果纯右值代替原操作数。
阶段 2
|
(C++11 起) |
阶段 3
|
(C++26 起) |
阶段 4
- 如果有一个操作数具有浮点类型,那么应用以下规则:
- 如果两个操作数具有相同类型,那么后续不会进行任何转换。
- 否则,如果有一个操作数具有非浮点类型,那么该操作数会转换到另一个操作数具有的(浮点)类型。
- 否则,如果两个操作数具有的类型的浮点转换等级有序但 (C++23 起)不相等,那么具有更低浮点转换等级的类型的操作数会转换到另一个操作数具有的(浮点转换等级更高的)类型。
|
(C++23 起) |
- 否则,两个操作数都具有整数类型,进入下一阶段。
阶段 5
将两个操作数都转换到公共类型 C
。给定类型 T1
和 T2
为两个操作数的(在整数提升规则下的)提升后类型,应用以下规则确定 C
:
- 如果
T1
和T2
是相同类型,那么C
是该类型。 - 否则,如果
T1
和T2
都是有符号整数类型或者都是无符号整数类型,那么C
是具有更高整数转换等级的类型。 - 否则,
T1
和T2
之中的一个类型是有符号整数类型S
,而另一个类型是无符号整数类型U
。应用以下规则:
- 如果
U
的整数转换等级高于或等于S
的整数转换等级,那么C
是U
。 - 否则,如果
S
可以表示U
的所有值,那么C
是S
。 - 否则,
C
是与S
对应的无符号整数类型。
- 如果
如果一个操作数具有枚举类型,而另一个操作数具有另一个枚举类型或浮点类型,那么行为被弃用。 |
(C++20 起) (C++26 前) |
整数转换等级
每个整数类型都有一个整数转换等级,定义如下:
- 除了 char 和 signed char(如果 char 有符号)以外的所有有符号整数类型的等级都不相同,即使它们的表示相同。
- 对于两个有符号整数类型,宽度更小的类型的等级低于宽度更大的类型的等级。
- 以下整数类型的等级递减:
|
(C++11 起) |
- long
- int
- short
- signed char
- 每个无符号整数类型的等级都等于对应的有符号整数类型的等级。
|
(C++11 起) |
- bool 的等级低于所有标准整数类型的等级。
- 编码字符类型(char、char8_t (C++20 起)、char16_t、char32_t (C++11 起) 和 wchar_t 的等级等于它们的底层类型的等级,也就是说:
- char 的等级等于 signed char 和 unsigned char 的等级。
|
(C++20 起) |
|
(C++11 起) |
- wchar_t 的等级等于它的由实现定义的底层类型的等级。
|
(C++11 起) |
- 对于所有整数类型
T1
、T2
和T3
,如果T1
的等级高于T2
的等级,并且T2
的等级高于T3
的等级,那么T1
的等级高于T3
的等级。
整数转换等级也用于定义整数提升。
浮点转换等级与子等级
浮点转换等级
每个浮点类型都有一个浮点转换等级,定义如下:
- 以下标准浮点类型的等级依次递减:
- long double
- double
- float
|
(C++23 起) |
浮点转换子等级浮点转换等级相等的浮点类型按浮点转换子等级 有序。该子等级在所有等级相等的类型中组成全序。
|
(C++23 起) |
用途
浮点转换等级和子等级也用于:
|
(C++23 起) |
- 确定 std::complex 的 转换构造函数是不是显式的
- 在传递具有不同浮点类型的实参到常用或特殊数学函数时确定公共浮点类型
缺陷报告
下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
缺陷报告 | 应用于 | 出版时的行为 | 正确行为 |
---|---|---|---|
CWG 1642 | C++98 | 一般算数转换可能会涉及左值 | 先应用左值到右值转换 |
CWG 2528 | C++20 | unsigned char 和 unsigned int 之间 的三路比较因为中途的整数提升而非良构[1] |
在实际没有进行整数提升的情况下 根据提升后类型确定公共类型[2] |
CWG 2892 | C++98 | 当两个操作数具有相同类型时,“后续不需要再进行转换”的含义不明确 | 改成“后续不会进行任何转换” |