Namespaces
Variants

Usual arithmetic conversions

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

许多期望操作数为 算术 类型或 枚举 类型的二元运算符会以类似方式引发类型转换并生成结果类型。其目的是产生一个公共类型,该类型同时也是结果的类型。这种模式被称为 常规算术转换

目录

定义

通常的算术转换定义如下:

第一阶段

对两个操作数应用 左值到右值转换 ,生成的纯右值将在后续处理过程中替代原始操作数。

阶段 2

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

阶段 3

  • 若任一操作数为 枚举类型 ,且另一操作数为不同枚举类型或浮点类型,则该表达式非良构。
  • 否则,进入下一阶段。
(since C++26)

阶段 4

  • 若两操作数类型相同,则不进行进一步转换。
  • 否则,若任一操作数为非浮点类型,则该操作数被转换为另一操作数的类型。
  • 否则,若操作数类型的 浮点转换等级 存在有序关系但不相等 (C++23 起) ,则浮点转换等级较低的操作数类型被转换为另一操作数的类型。
  • 否则,若操作数类型的浮点转换等级相同,则具有较 低浮点转换子等级 的操作数将被转换为另一操作数的类型。
  • 否则,该表达式非良构。
(since 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 对应的无符号整数类型。

如果一个操作数是枚举类型,另一个操作数是不同的枚举类型或浮点类型,此行为已被弃用。

(since C++20)
(until C++26)

整数转换等级

每个 整数类型 都具有按如下方式定义的 整数转换等级

  • 除了 char signed char (若 char 为有符号类型)之外,没有两个有符号整数类型具有相同等级,即使它们具有相同的表示形式。
  • 有符号整数类型的等级大于任何宽度更小的有符号整数类型的等级。
  • 下列整数类型的等级按顺序递减:
  • long long
(自 C++11 起)
  • long
  • int
  • short
  • signed char
  • 任何无符号整数类型的等级等于对应的有符号整数类型的等级。
  • 任何标准整数类型的等级都高于具有相同宽度的任何扩展整数类型的等级。
(since C++11)
  • bool 的等级低于所有标准整数类型的等级。
  • 编码字符类型( char char8_t (C++20 起) char16_t char32_t (C++11 起) wchar_t )的等级等于其 底层类型 的等级,这意味着:
  • char 的等级等于 signed char unsigned char 的等级。
  • char8_t 的等级等于 unsigned char 的等级。
(since C++20)
(since C++11)
  • wchar_t 的等级等于其实现定义的底层类型的等级。
  • 任何扩展有符号整数类型相对于具有相同宽度的其他扩展有符号整数类型的等级由实现定义,但仍需遵循确定整数转换等级的其他规则。
(since C++11)
  • 对于所有整数类型 T1 T2 T3 ,若 T1 的等级高于 T2 T2 的等级高于 T3 ,则 T1 的等级高于 T3

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

浮点转换等级与子等级

浮点转换等级

每个 浮点类型 都具有按如下方式定义的 浮点转换等级

  • 标准浮点类型的等级按以下顺序递减:
    • long double
    • double
    • float
  • 浮点类型 T 的等级高于其值集是 T 值集真子集的任何浮点类型的等级。
  • 具有相同值集的两个扩展浮点类型具有相等的等级。
  • 与恰好一个 cv 非限定标准浮点类型具有相同值集的扩展浮点类型,其等级等于该标准浮点类型的等级。
  • 与多个 cv 非限定标准浮点类型具有相同值集的扩展浮点类型,其等级等于 double 的等级。
(since C++23)


浮点转换子级

具有相同浮点转换等级的浮点类型通过 浮点转换子级 进行排序。该子级在具有相同等级的类型间形成全序关系。

类型 std::float16_t , std::float32_t , std::float64_t std::float128_t ( 固定宽度浮点类型 ) 的转换子级高于任何具有相同转换等级的标准浮点类型。其余情况下,转换子级的顺序由实现定义。

(since C++23)

用法

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

(since 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 而无需经过中间整型提升。该转换不属于窄化转换,因此三路比较的格式正确。