一般算术转换

来自cppreference.com
< cpp‎ | language
 
 
 
表达式
概述
值类别(左值 lvalue、右值 rvalue、亡值 xvalue)
求值顺序(序列点)
常量表达式
潜在求值表达式
初等表达式
lambda 表达式(C++11)
字面量
整数字面量
浮点字面量
布尔字面量
字符字面量,包含转义序列
字符串字面量
空指针字面量(C++11)
用户定义字面量(C++11)
运算符
赋值运算符a=ba+=ba-=ba*=ba/=ba%=ba&=ba|=ba^=ba<<=ba>>=b
自增与自减++a--aa++a--
算术运算符+a-aa+ba-ba*ba/ba%b~aa&ba|ba^ba<<ba>>b
逻辑运算符a||ba&&b!a
比较运算符a==ba!=ba<ba>ba<=ba>=ba<=>b(C++20)
成员访问运算符a[b]*a&aa->ba.ba->*ba.*b
其他运算符a(...)a,ba?b:c
new 表达式
delete 表达式
throw 表达式
alignof
sizeof
sizeof...(C++11)
typeid
noexcept(C++11)
折叠表达式(C++17)
运算符的代用表示
优先级和结合性
运算符重载
默认比较(C++20)
类型转换
隐式转换
一般算术转换
const_cast
static_cast
reinterpret_cast
dynamic_cast
显式转换 (T)a, T(a)
用户定义转换
 

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

定义

一般算数转换定义如下:

阶段 1

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

阶段 2

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

阶段 3

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

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

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

(C++20 起)

整数转换等级

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

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

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


浮点转换等级与子等级

浮点转换等级

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

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

浮点转换子等级

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

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

用途

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

(C++23 起)

缺陷报告

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

缺陷报告 应用于 出版时的行为 正确行为
CWG 2528 C++20 unsigned charunsigned int 之间
的三路比较因为中途的整数提升而非良构[1]
在实际没有进行整数提升的情况下
根据提升后类型确定公共类型[2]
  1. 在缺陷解决前,unsigned char 会在阶段 3 开始时提升到 int,然后再转换到 unsigned int。然而后者是窄化转换,导致三路比较非良构。
  2. 在缺陷解决后,公共类型还是 unsigned int。但不同的地方在于 unsigned char 会在中途没有整数提升的情况下直接转换到 unsigned int。该转换不是窄化转换,因此三路比较良构。