一般算术转换

来自cppreference.com
< cpp‎ | language


 
 
C++ 语言
 
 

许多期待具有算术类型枚举类型的操作数的二元运算符会以相似的方法进行转换并产生结果类型。这样做的目的是产生公共类型,也就是结果类型。该模式被称为一般算术转换

定义

一般算数转换定义如下:

阶段 1

对两个操作数进行左值到右值转换,在后续过程中将转换结果纯右值代替原操作数。

阶段 2

  • 如果有一个操作数具有有作用域枚举类型,那么不会进行任何转换;如果另一个操作数的类型不同,那么表达式非良构。
  • 否则进入下一阶段。
(C++11 起)

阶段 3

  • 如果有一个操作数具有枚举类型,而另一个操作数具有另一个枚举类型或浮点类型,那么表达式非良构。
  • 否则进入下一阶段。
(C++26 起)

阶段 4

  • 如果有一个操作数具有浮点类型,那么应用以下规则:
  • 如果两个操作数具有相同类型,那么后续不会进行任何转换。
  • 否则,如果有一个操作数具有非浮点类型,那么该操作数会转换到另一个操作数具有的(浮点)类型。
  • 否则,如果两个操作数具有的类型的浮点转换等级有序但 (C++23 起)不相等,那么具有更低浮点转换等级的类型的操作数会转换到另一个操作数具有的(浮点转换等级更高的)类型。
  • 否则,如果两个操作数具有的类型的浮点转换等级相等,那么具有更低浮点转换子等级的类型的操作数会转换到另一个操作数具有的(浮点转换子等级更高的)类型。
  • 否则,表达式非良构。
(C++23 起)
  • 否则,两个操作数都具有整数类型,进入下一阶段。

阶段 5

将两个操作数都转换到公共类型 C。给定类型 T1T2 为两个操作数的(在整数提升规则下的)提升后类型,应用以下规则确定 C

  • 如果 T1T2 是相同类型,那么 C 是该类型。
  • 否则,如果 T1T2 都是有符号整数类型或者都是无符号整数类型,那么 C 是具有更高整数转换等级的类型。
  • 否则,T1T2 之中的一个类型是有符号整数类型 S,而另一个类型是无符号整数类型 U。应用以下规则:
  • 如果 U 的整数转换等级高于或等于 S 的整数转换等级,那么 CU
  • 否则,如果 S 可以表示 U 的所有值,那么 CS
  • 否则,C 是与 S 对应的无符号整数类型。

如果一个操作数具有枚举类型,而另一个操作数具有另一个枚举类型或浮点类型,那么行为被弃用。

(C++20 起)
(C++26 前)

整数转换等级

每个整数类型都有一个整数转换等级,定义如下:

  • 除了 charsigned char(如果 char 有符号)以外的所有有符号整数类型的等级都不相同,即使它们的表示相同。
  • 对于两个有符号整数类型,宽度更小的类型的等级低于宽度更大的类型的等级。
  • 以下整数类型的等级递减:
  • long long
(C++11 起)
  • long
  • int
  • short
  • signed char
  • 每个无符号整数类型的等级都等于对应的有符号整数类型的等级。
  • 每个标准整数类型的等级都高于具有相同宽度的扩展整数类型的等级。
(C++11 起)
  • bool 的等级低于所有标准整数类型的等级。
  • 编码字符类型(charchar8_t (C++20 起)char16_tchar32_t (C++11 起)wchar_t 的等级等于它们的底层类型的等级,也就是说:
  • char 的等级等于 signed charunsigned char 的等级。
  • char8_t 的等级等于 unsigned char 的等级。
(C++20 起)
(C++11 起)
  • wchar_t 的等级等于它的由实现定义的底层类型的等级。
  • 扩展有符号整数类型的等级,相对于另一相同宽度的扩展有符号整数类型的高低由实现定义,但不能违背确定整数转换等级的其他规则。
(C++11 起)
  • 对于所有整数类型 T1T2T3,如果 T1 的等级高于 T2 的等级,并且 T2 的等级高于 T3 的等级,那么 T1 的等级高于 T3 的等级。

整数转换等级也用于定义整数提升

浮点转换等级与子等级

浮点转换等级

每个浮点类型都有一个浮点转换等级,定义如下:

  • 以下标准浮点类型的等级依次递减:
    • long double
    • double
    • float
  • 对于每对浮点类型 T1T2,如果 T1 能表示的所有值的集合是 T2 能表示的所有值的集合的真子集,那么 T1 的等级低于 T2
  • 两个能表示的值的集合相同的扩展浮点类型的等级相等。
  • 如果一个扩展浮点类型能表示的所有值的集合与正好一个无 cv 限定的标准浮点类型能表示的所有值的集合相同,那么该扩展浮点类型的等级等于该标准浮点类型的等级。
  • 如果一个扩展浮点类型能表示的所有值的集合与两个或更多无 cv 限定的标准浮点类型能表示的所有值的集合相同,那么该扩展浮点类型的等级等于 double 的等级。
(C++23 起)


浮点转换子等级

浮点转换等级相等的浮点类型按浮点转换子等级 有序。该子等级在所有等级相等的类型中组成全序。

std::float16_tstd::float32_tstd::float64_tstd::float128_t 类型(定宽浮点类型)的浮点转换子等级大于所有浮点转换等级相等的标准整数类型的浮点转换子等级。否则,浮点转换子等级的高低由实现定义。

(C++23 起)

用途

浮点转换等级和子等级也用于:

(C++23 起)

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告 应用于 出版时的行为 正确行为
CWG 1642 C++98 一般算数转换可能会涉及左值 先应用左值到右值转换
CWG 2528 C++20 unsigned charunsigned int 之间
的三路比较因为中途的整数提升而非良构[1]
在实际没有进行整数提升的情况下
根据提升后类型确定公共类型[2]
CWG 2892 C++98 当两个操作数具有相同类型时,“后续不需要再进行转换”的含义不明确 改成“后续不会进行任何转换”
  1. 在缺陷解决前,unsigned char 会在阶段 5 开始时提升到 int,然后再转换到 unsigned int。然而后者是窄化转换,导致三路比较非良构。
  2. 在缺陷解决后,公共类型还是 unsigned int。但不同的地方在于 unsigned char 会在中途没有整数提升的情况下直接转换到 unsigned int。该转换不是窄化转换,因此三路比较良构。