命名空间
变体
操作

常用算术转换

来自 cppreference.cn
< cpp‎ | 语言
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句(循环)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (直到 C++17*)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

许多期待算术枚举类型操作数的二元运算符,会以类似的方式引发转换并产生结果类型。其目的是产生一个公共类型,该类型也是结果的类型。此模式被称为常规算术转换(usual arithmetic conversions)

目录

[编辑] 定义

常规算术转换定义如下

[编辑] 阶段 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)

[编辑] 整数转换等级

每个整数类型都有一个整数转换等级(integer conversion rank),定义如下

  • 除了 charsigned char(如果 char 是有符号的),没有两个有符号整数类型具有相同的等级,即使它们具有相同的表示。
  • 一个有符号整数类型的等级,大于任何宽度更小的有符号整数类型的等级。
  • 以下整数类型的等级依次降低
  • long long
(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 charunsigned char 的等级。
  • char8_t 的等级等于 unsigned char 的等级。
(C++20 起)
(C++11 起)
  • wchar_t 的等级等于其由实现定义的底层类型的等级。
  • 任何扩展有符号整数类型相对于另一个具有相同宽度的扩展有符号整数类型的等级是由实现定义的,但仍需遵守确定整数转换等级的其他规则。
(C++11 起)
  • 对于所有整数类型 T1T2T3,如果 T1 的等级高于 T2,且 T2 的等级高于 T3,则 T1 的等级高于 T3

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

[编辑] 浮点转换等级和次等级

[编辑] 浮点转换等级

每个浮点类型都有一个浮点转换等级(floating-point conversion rank),定义如下

  • 标准浮点类型的等级依次降低
    • long double
    • double
    • float
  • 一个浮点类型 T 的等级,大于任何其值集合是 T 的值集合的真子集的浮点类型的等级。
  • 两个具有相同值集合的扩展浮点类型等级相等。
  • 一个其值集合与某个 cv-无限定标准浮点类型完全相同的扩展浮点类型,其等级与该标准浮点类型的等级相等。
  • 一个其值集合与多个 cv-无限定标准浮点类型完全相同的扩展浮点类型,其等级与 double 的等级相等。
(C++23 起)


浮点转换次等级

浮点转换等级相等的浮点类型,通过浮点转换次等级(floating-point conversion subrank)来排序。次等级在等级相等的类型之间构成一个全序关系。

类型 std::float16_tstd::float32_tstd::float64_tstd::float128_t固定宽度浮点类型)的转换次等级高于任何具有相同转换等级的标准浮点类型。否则,转换次等级的顺序是由实现定义的。

(C++23 起)

[编辑] 用法

浮点转换等级和次等级也用于

(C++23 起)

[编辑] 缺陷报告

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

缺陷报告 应用于 发布时的行为 正确的行为
CWG 1642 C++98 常规算术转换可能涉及左值 首先应用左值到右值转换
CWG 2528 C++20 unsigned char
unsigned int 之间的三路比较非良构,因为
存在中间的整数提升[1]
基于提升后的类型确定
公共类型,而不需要
实际提升操作数[2]
CWG 2892 C++98 当两个操作数都是相同的
浮点类型时,“不需要
进一步转换”的含义不明确
更改为“不会执行
进一步转换”
  1. 在解决此问题前,unsigned char 在阶段 5 开始时被提升为 int,然后被转换为 unsigned int。然而,后一个转换是窄化转换,这使得三路比较非良构。
  2. 在解决此问题后,公共类型仍然是 unsigned int。不同之处在于 unsigned char 被直接转换为 unsigned int,而没有中间的整数提升。该转换不是窄化转换,因此三路比较是良构的。