Namespaces
Variants

Implicit 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
Implicit conversions
static_cast
const_cast
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

当某种类型 T1 的表达式被用于不接受该类型但接受其他类型 T2 的上下文时,就会执行隐式转换;具体包括:

  • 当表达式作为实参传递给声明参数类型为 T2 的函数时;
  • 当表达式作为操作数与期望 T2 类型的运算符一起使用时;
  • 当初始化类型为 T2 的新对象时,包括返回 T2 类型的函数中的 return 语句;
  • 当表达式用于 switch 语句时( T2 为整型);
  • 当表达式用于 if 语句或循环时( T2 bool 类型)。

当且仅当存在从 T1 T2 的唯一明确 隐式转换序列 时,该程序才是良构的(可编译的)。

如果被调用的函数或运算符存在多个重载版本,在从 T1 到每个可用 T2 的隐式转换序列构建完成后,将通过 重载决议 规则决定最终编译哪个重载版本。

注意:在算术表达式中,二元运算符操作数隐式转换的目标类型由另一套独立规则决定: 常用算术转换

目录

转换顺序

隐式转换序列按以下顺序组成:

1) 零个或一个 标准转换序列
2) 零次或一次 用户定义转换
3) 零次或一次 标准转换序列 (仅当使用用户定义转换时适用)。

当考虑构造函数或用户定义转换函数的参数时,只允许存在一个标准转换序列(否则用户定义转换可能会形成有效链式调用)。当从一个非类类型转换到另一个非类类型时,只允许使用标准转换序列。

标准转换序列按以下顺序组成:

1) 允许零次或一次来自以下集合的转换:
  • 左值到右值转换
  • 数组到指针转换 ,以及
  • 函数到指针转换
2) 零次或一次 数值提升 数值转换
3) 零次或一次 函数指针转换
(since C++17)
4) 零次或一次 限定转换

用户定义转换由零个或一个非显式单参数 转换构造函数 或非显式 转换函数 调用组成。

当且仅当 T2 能从 e 进行 拷贝初始化 时,表达式 e 被称为 可隐式转换为 T2 ,即声明语句 T2 t = e ; 对于某个虚构的临时变量 t 是合法(可编译)的。注意这与 直接初始化 T2 t ( e ) )不同,后者还会考虑显式构造函数和转换函数。

上下文转换

在以下语境中,期望出现 bool 类型,且当声明 bool t ( e ) ; 合法时(即考虑如 explicit T :: operator bool ( ) const ; 这类显式转换函数),会进行隐式转换。此类表达式 e 被称为 上下文ually转换为 bool

  • if while for 的控制表达式;
  • 内置逻辑运算符 ! && || 的操作数;
  • 条件运算符 ?: 的第一个操作数;
  • static_assert 声明中的谓词;
  • noexcept 说明符中的表达式;
(since C++20)
(since C++11)

在以下语境中,期望使用上下文特定类型 T ,而类类型 E 的表达式 e 仅在满足以下条件时被允许:

(直至 C++14)
  • 在允许类型中恰好存在一个类型 T ,使得 E 具有返回类型为(可能 cv 限定的) T 或(可能 cv 限定的) T 的引用的非显式转换函数,且
  • e 可隐式转换为 T
(自 C++14 起)

此类表达式 e 被称为被 上下文隐式转换 为指定类型 T 注意显式转换函数不会被考虑,尽管它们在向 bool 的上下文转换中会被考虑。 (C++11 起)

#include <cassert>
template<typename T>
class zero_init
{
    T val;
public:
    zero_init() : val(static_cast<T>(0)) {}
    zero_init(T val) : val(val) {}
    operator T&() { return val; }
    operator T() const { return val; }
};
int main()
{
    zero_init<int> i;
    assert(i == 0);
    i = 7;
    assert(i == 7);
    switch (i) {}     // C++14 之前的错误(存在多个转换函数)
                      // C++14 起正常(两个函数都转换为相同的 int 类型)
    switch (i + 0) {} // 始终正常(隐式转换)
}

值转换

值变换是改变表达式 值类别 的转换。当表达式作为运算符的操作数出现,而该运算符期望不同值类别的表达式时,就会发生值变换:

  • 当泛左值作为需要纯右值操作数的运算符操作数出现时,会应用 左值到右值转换 数组到指针转换 函数到指针转换 标准转换,将表达式转换为纯右值。
  • 除非另有说明,当纯右值作为期望该操作数为泛左值的运算符的操作数出现时,将应用 临时物化转换 将该表达式转换为亡值。
(since C++17)

左值到右值转换

一个 左值 (C++11 前) 一个 泛左值 (C++11 起) ,其类型为任何非函数、非数组类型 T ,可以隐式转换为 一个 右值 (C++11 前) 一个 纯右值 (C++11 起)

  • 如果 T 不是类类型,则该 右值 (C++11 前) 纯右值 (C++11 起) 的类型是 T 的 cv 非限定版本。
  • 否则,该 右值 (C++11 前) 纯右值 (C++11 起) 的类型是 T

如果程序需要对 不完整类型 进行左值到右值的转换,则该程序是非良构的。

给定 lvalue (until C++11) glvalue (since C++11) 所引用的对象为 obj

  • 转换结果是 obj 包含的值。如果 T obj 的类型中一个是带符号整数类型,另一个是对应的无符号整数类型,则结果是类型为 T 且与 obj 具有相同值表示的值。
(C++11 前)
  • 当对表达式 E 应用左值到右值转换时,在以下情况下不会访问 obj 包含的值:
  • 转换结果按以下方式确定:
  • 如果 T 是(可能带有 cv 限定符的) std::nullptr_t ,则结果为 空指针常量 。转换不会访问 obj ,因此即使 T 带有 volatile 限定符也不会产生副作用,且该泛左值可以引用联合体的非活跃成员。
  • 否则,如果 T 是类类型:
(C++17 前)
(C++17 起)
  • 否则,如果 obj 包含无效指针值,则行为由实现定义。
  • 否则,如果 obj 值表示 中的位对于 obj 的类型无效,则行为未定义。
  • 否则, obj 被读取,且 (C++20 起) 结果是 obj 包含的值。如果 T obj 的类型中一个是带符号整数类型,另一个是对应的无符号整数类型,则结果是类型为 T 且与 obj 具有相同值表示的值。
(C++11 起)

此转换模拟了将值从内存位置读取到 CPU 寄存器的操作。

数组到指针转换

类型为“ N T 的数组”或“未知边界 T 数组”的 左值 右值 ,可隐式转换为类型“指向 T 的指针”的 纯右值 若该数组为纯右值,则发生 临时物化 (C++17 起) 结果指针指向数组的首元素(详见 数组到指针退化 )。

函数到指针转换

一个 左值 函数类型可以隐式转换为指向该函数的 纯右值 指针 。这不适用于非静态成员函数,因为不存在引用非静态成员函数的左值。

临时物化

任何完整类型 T 纯右值 可转换为同类型 T 的亡值。此转换通过以临时对象作为结果对象对纯右值求值,从而初始化一个类型为 T 的 临时对象 ,并生成指向该临时对象的亡值。

T 是类类型或类类型数组,则其必须具有可访问且未删除的析构函数。

struct S { int m; };
int i = S().m; // 自 C++17 起成员访问期待泛左值;
               // S() 纯右值被转换为亡值

临时物化在以下情形发生:

注意:当从同类型纯右值初始化对象时(通过 直接初始化 拷贝初始化 ),临时物化 不会 发生:该对象直接从初始化器初始化。这确保了“保证的拷贝消除”。

(C++17 起)

整型提升

纯右值 的小型整型类型(如 char )和无作用域枚举类型可转换为较大整型类型(如 int )的纯右值。特别地, 算术运算符 不接受小于 int 的类型作为参数,若适用时,整型提升会在左值到右值转换后自动执行。此转换始终保留原值。

以下本节中的隐式转换被归类为 整型提升

请注意,对于给定的源类型,整型提升的目标类型是唯一的,所有其他转换都不属于提升。例如, 重载决议 会优先选择 char -> int (提升)而非 char -> short (转换)。

整型提升

类型为 bool 的纯右值可转换为类型为 int 的纯右值,其中 false 转换为 0 true 转换为 1

对于除 bool 之外的整型 T 的纯右值 val

1) val 是对 位域 应用左值到右值转换的结果:
  • int 能表示该位域的所有值,则 val 可转换为 int 类型的纯右值;
  • 否则,若 unsigned int 能表示该位域的所有值,则 val 可转换为 unsigned int
  • 否则, val 可按第(3)项规定的规则进行转换。
2) 否则( val 不是从位域转换而来):
  • T char8_t , (C++20 起) char16_t , char32_t (C++11 起) wchar_t ,则 val 可按第 (3) 项规则转换;
  • 否则,若 T 整数转换等级 低于 int 的等级:
  • int 能表示 T 的所有值,则 val 可转换为类型为 int 的纯右值;
  • 否则, val 可转换为类型为 unsigned int 的纯右值。
3) 在符合第(1)项(转换后的位域无法容纳于 unsigned int )或第(2)项( T 为指定字符类型)的情况下, val 可被转换为以下类型中首个能表示其底层类型所有值的纯右值:
  • int
  • unsigned int
  • long
  • unsigned long
  • long long
  • unsigned long long
  • T 的底层类型
(C++11 起)

枚举类型的提升

底层类型未固定的无作用域 枚举 类型的纯右值,可转换为以下列表中首个能容纳其整个值范围的类型的纯右值:

  • int
  • unsigned int
  • long
  • unsigned long
  • 整数转换等级 高于 long long
  • 其整数转换等级在所有扩展整数类型中为最低,且
  • 若存在两个整数转换等级最低的扩展整数类型,则该类型为有符号类型。
(自 C++11 起)


底层类型固定的无作用域枚举类型的纯右值可转换为其底层类型。此外,若底层类型同样适用于整型提升,则可转换为提升后的底层类型。就 重载决议 而言,转换为未提升的底层类型是更优选择。

(since C++11)

浮点提升

类型为 float 纯右值 可被转换为类型为 double 的纯右值。该值保持不变。

这种转换称为 浮点提升

数值转换

与提升不同,数值转换可能会改变数值,并可能导致精度损失。

整型转换

整数类型或非限定作用域枚举类型的 纯右值 可转换为任意其他整数类型。若该转换属于整型提升范畴,则视为提升而非转换。

  • 若目标类型为无符号类型,则结果值等于源值对 2 n
    取模的最小无符号值,其中 n 表示目标类型的位宽。
  • 也就是说,根据目标类型是更宽还是更窄,有符号整数会进行符号扩展 [1] 或截断处理,而无符号整数则会分别进行零扩展或截断处理。
  • 若目标类型为有符号类型,且源整数值可在目标类型中表示,则值不变。否则结果是 由实现定义 (C++20 前) 目标类型中等于源值模 2 n
    的唯一值,其中 n 是用于表示目标类型的位数
    (C++20 起)
    (注意这与 有符号整数算术溢出 不同,后者是未定义行为)。
  • 若源类型是 bool ,则值 false 被转换为零,值 true 被转换为目标类型的值一(注意若目标类型是 int ,此为整数提升而非整数转换)。
  • 若目标类型是 bool ,此为 布尔转换 (见下文)。
  1. 此规则仅适用于二进制补码算术运算,而该运算仅对 精确宽度整数类型 是强制要求的。但需注意,目前所有支持C++编译器的平台均采用二进制补码算术。

浮点转换

浮点类型的 纯右值 可被转换为其他任意浮点类型的纯右值。

(C++23 前)

浮点类型的 纯右值 可被转换为具有更高或相等 浮点转换等级 的其他任意浮点类型的纯右值。

标准浮点类型的 纯右值 可被转换为其他任意标准浮点类型的纯右值。

可使用 static_cast 显式将浮点类型的纯右值转换为其他任意浮点类型。

(C++23 起)

如果转换列在浮点提升下,则它是提升而非转换。

  • 若源值在目标类型中能够精确表示,则其值保持不变。
  • 若源值介于目标类型的两个可表示值之间,则结果为这两个值之一(具体选择哪个值由实现定义,但若支持IEEE算术,默认采用 就近舍入 规则)。
  • 否则,行为未定义。

浮点-整型转换

浮点类型的 纯右值 可转换为任意整数类型的纯右值。小数部分会被截断,即直接舍弃小数部分。

  • 如果截断后的值无法放入目标类型,则行为未定义(即使目标类型是无符号类型,模运算也不适用)。
  • 如果目标类型是 bool ,这属于布尔转换(参见 下文 )。

整数或无作用域枚举类型的纯右值可转换为任何浮点类型的纯右值。若可能,结果将是精确的。

  • 如果该值能够容纳到目标类型中但无法精确表示,具体选择最接近的高位可表示值还是最接近的低位可表示值由实现定义,但如果支持 IEEE 算术,默认采用 就近舍入 规则。
  • 如果该值无法容纳到目标类型中,则行为未定义。
  • 如果源类型是 bool ,则值 false 被转换为零,值 true 被转换为一。

指针转换

一个 空指针常量 可以转换为任意指针类型,转换结果是该类型的空指针值。这种转换(称为 空指针转换 )允许直接转换为cv限定类型作为单次转换,即不被视为数值转换和限定转换的组合。

指向任何(可选地带有 cv 限定符)对象类型 T 纯右值 指针可转换为指向(具有相同 cv 限定符的) void 的纯右值指针。转换后的指针与原始指针值指向内存中的同一位置。

  • 若原指针为空指针值,则结果为目标类型的空指针值。

一个类型为“指向(可能带有 cv 限定符的) Derived 的指针”的纯右值 ptr ,可被转换为类型“指向(可能带有 cv 限定符的) Base 的指针”的纯右值,其中 Base Derived 基类 ,且 Derived 完整 的类类型。若 Base 不可访问或存在二义性,则程序非良构。

  • ptr 是空指针值,则结果同样是空指针值。
  • 否则,若 Base Derived 虚基类 ,且 ptr 未指向一个类型与 Derived 相似 、且处于其 生存期 或构造/析构期间的对象,则行为未定义。
  • 否则,结果将指向派生类对象的基类子对象。

指向成员指针的转换

一个 空指针常量 可以转换为任意成员指针类型,转换结果是该类型的空成员指针值。这种转换(称为 空成员指针转换 )允许直接转换为cv限定类型,即不被视为数值转换和限定转换的组合。

一个类型为“指向 Base 类成员(类型为可能带有cv限定符的 T )的指针”的 纯右值 ,可转换为类型为“指向 Derived 类成员(类型为完全相同的cv限定符的 T )的指针”的纯右值,其中 Base Derived 的基类,且 Derived 是完整类类型。若 Base Derived 的不可访问基类、歧义基类、虚基类,或是 Derived 某个中间虚基类的基类,则程序非良构。

  • 如果 Derived 不包含原始成员且不是包含原始成员的类的基类,则行为未定义。
  • 否则,生成的指针可以通过 Derived 对象解引用,并将访问该 Derived 对象中 Base 基类子对象内的成员。

布尔转换

整型、浮点型、无作用域枚举类型、指针类型及成员对象指针类型的 纯右值 可转换为 bool 类型的纯右值。

值为零(对于整型、浮点型和无作用域枚举)以及空指针和空成员指针值会变为 false 。所有其他值会变为 true

直接初始化 的语境中, bool 对象可以通过类型为 std::nullptr_t 的纯右值(包括 nullptr )进行初始化。其结果为 false 。但此行为不被视为隐式转换。

(since C++11)

限定性转换

一般来说:

  • 类型为指向 cv限定 类型 T 的指针的纯右值,可转换为指向具有更多cv限定(即可以添加const和volatile限定符)的相同类型 T 的指针纯右值。
  • 类型为指向类 X 中cv限定类型 T 成员指针的纯右值,可转换为指向类 X 具有更多cv限定 类型 T 成员指针的纯右值。

“限定转换”的形式化定义在 下文 给出。

相似类型

非正式地说,如果忽略顶层 cv 限定符,两种类型是 相似 的:

  • 它们是相同类型;或
  • 它们都是指针,且所指向的类型相似;或
  • 它们都是指向同一类成员的指针,且所指向的成员类型相似;或
  • 它们都是数组,且数组元素类型相似。

例如:

  • const int * const * int ** 是相似的;
  • int ( * ) ( int * ) int ( * ) ( const int * ) 不是相似的;
  • const int ( * ) ( int * ) int ( * ) ( int * ) 不是相似的;
  • int ( * ) ( int * const ) int ( * ) ( int * ) 是相似的(它们是同一类型);
  • std:: pair < int , int > std:: pair < const int , int > 不是相似的。

形式上,类型相似性是通过限定分解来定义的。

类型的 限定符分解 是指一组分量 cv_i P_i 构成的序列,使得类型 T 可表示为“ cv_0 P_0 cv_1 P_1 ... cv_n−1 P_n−1 cv_n U ”,其中 n 为非负整数。

  • 每个 cv_i 是一组 const volatile 限定符,且
  • 每个 P_i
  • “指向”,
  • “指向 C_i 类成员的指针,其类型为”,
  • N_i 个元素的数组”,或
  • “未知边界数组”。

如果 P_i 表示数组,则元素类型上的 cv 限定符 cv_i+1 也会被视为数组的 cv 限定符 cv_i

// T 是“指向常量整型指针的指针”,它有 3 层限定符分解:
// n = 0 -> cv_0 为空,U 是“指向常量整型指针的指针”
// n = 1 -> cv_0 为空,P_0 是“指向”,
//          cv_1 为空,U 是“指向常量整型的指针”
// n = 2 -> cv_0 为空,P_0 是“指向”,
//          cv_1 为空,P_1 是“指向”,
//          cv_2 是“const”,U 是“整型”
using T = const int**;
// 将以下任意类型代入 U 可得到对应的分解:
// U = U0 -> 对应 n = 0 的分解:U0
// U = U1 -> 对应 n = 1 的分解:指向 [U1] 的指针
// U = U2 -> 对应 n = 2 的分解:指向 [指向 [常量 U2]] 的指针
using U2 = int;
using U1 = const U2*;
using U0 = U1*;

两种类型 T1 T2 相似 的,如果存在它们各自的限定分解,且两个限定分解满足以下所有条件:

  • 它们具有相同的 n
  • U 表示的类型相同。
  • 对应的 P_i 组件对于所有 i 都相同 或者一个是“ N_i 的数组”而另一个是“未知边界的数组” (C++20 起)
// 限定符分解(n = 2 的情况):
// 指向[指向[const int]的volatile指针]的指针
using T1 = const int* volatile *;
// 限定符分解(n = 2 的情况):
// 指向[指向[int]的指针]的const指针
using T2 = int** const;
// 对于上述两种限定符分解
// 尽管 cv_0、cv_1 和 cv_2 均不相同
// 但它们具有相同的 n、U、P_0 和 P_1
// 因此类型 T1 和 T2 是相似的

cv限定符的组合

在以下描述中,类型 Tn 的最长限定分解记作 Dn ,其组成部分记作 cvn_i Pn_i

若满足以下所有条件,则类型为 T1 的纯右值表达式可转换为类型 T2

  • T1 T2 相似。
  • 对于每个非零 i ,若 const 存在于 cv1_i 中,则 const 也必须存在于 cv2_i 中,对于 volatile 同理。
  • 对于每个非零 i ,若 cv1_i cv2_i 不同,则对于 [ 1 , i ) 范围内的每个 k const 必须存在于 cv2_k 中。

两种类型 T1 T2 限定符合并类型 是一个与 T1 相似的类型 T3 ,满足:

  • cv3_0 为空,
  • 对于每个非零 i cv3_i cv1_i cv2_i 的并集,且
  • cv3_i cv1_i c2_i 不同,则对于 [ 1 , i ) 范围内的每个 k ,会向 cv3_k 添加 const
(C++20 前)

两种类型 T1 T2 限定符合并类型 是一个与 T1 相似的类型 T3 ,其中 D3 满足以下所有条件:

  • cv3_0 为空。
  • 对于每个非零 i cv3_i cv1_i cv2_i 的并集。
  • P1_i P2_i 为“未知边界数组”,则 P3_i 为“未知边界数组”,否则为 P1_i
  • cv3_i cv1_i cv2_i 不同,或 P3_i P1_i P2_i 不同,则对于 [ 1 , i ) 范围内的每个 k ,会向 cv3_k 添加 const

T1 T2 的限定符合并类型是无 cv 限定的 T2 ,则类型为 T1 的纯右值可转换为类型 T2

(C++20 起)
// T1 的最长限定符分解(n = 2):
// 指向 [指向 [char] 的指针] 的指针
using T1 = char**;
// T2 的最长限定符分解(n = 2):
// 指向 [指向 [const char] 的指针] 的指针
using T2 = const char**;
// 确定 D3 的 cv3_i 和 T_i 分量(n = 2):
// cv3_1 = 空(空 cv1_1 与空 cv2_1 的并集)
// cv3_2 = “const”(空 cv1_2 与 “const” cv2_2 的并集)
// P3_0 = “指向”(无未知边界数组,使用 P1_0)
// P3_1 = “指向”(无未知边界数组,使用 P1_1)
// 除 cv_2 外所有分量相同,cv3_2 与 cv1_2 不同,
// 因此为每个 k ∈ [1, 2) 的 cv3_k 添加 “const”:cv3_1 变为 “const”。
// T3 是“指向 const 指针的指针,该指针指向 const char”,即 const char* const *。
using T3 = /* T1 和 T2 的限定符合并类型 */;
int main()
{
    const char c = 'c';
    char* pc;
    T1 ppc = &pc;
    T2 pcc = ppc; // 错误:T3 与 cv 非限定 T2 类型不同,
                  //        无隐式转换。
    *pcc = &c;
    *pc = 'C';    // 若允许上述错误赋值,
                  // const 对象 “c” 可能被修改。
}

请注意在C语言中, const / volatile 仅能添加在第一层级:

char** p = 0;
char * const* p1 = p;       // 在 C 和 C++ 中均有效
const char* const * p2 = p; // 在 C 中错误,在 C++ 中有效

函数指针转换

  • 指向不抛出异常函数的纯右值指针可转换为指向可能抛出异常函数的纯右值指针。
  • 指向不抛出异常成员函数的纯右值指针可转换为指向可能抛出异常成员函数的纯右值指针。
void (*p)();
void (**pp)() noexcept = &p; // error: cannot convert to pointer to noexcept function
struct S
{
    typedef void (*p)();
    operator p();
};
void (*q)() noexcept = S(); // error: cannot convert to pointer to noexcept function
(C++17 起)

安全布尔问题

在C++11之前,设计一个可用于布尔上下文的类(例如 if ( obj ) { ... } )存在一个问题:给定用户定义的转换函数,如 T :: operator bool ( ) const ; ,隐式转换序列允许在该函数调用后额外添加一个标准转换序列,这意味着生成的 bool 值可以转换为 int ,从而允许出现诸如 obj << 1 ; int i = obj ; 的代码。

针对此问题的早期解决方案可见于 std::basic_ios ,它最初定义了 operator void * ,使得诸如 if ( std:: cin ) { ... } 的代码能够编译通过,因为 void * 可转换为 bool ;但 int n = std:: cout ; 无法编译,因为 void * 不可转换为 int 。这种方式仍允许无意义代码(例如 delete std:: cout ; )通过编译。

许多C++11之前的第三方库采用了一种更为精细的解决方案,即 安全布尔惯用法 std::basic_ios 也通过 LWG问题468 支持此惯用法,且 operator void * 已被替代(参见 注释 )。

自 C++11 起, explicit bool 转换 也可用于解决安全布尔问题。

缺陷报告

下列行为变更缺陷报告被追溯应用于先前发布的C++标准。

缺陷报告 适用标准 发布时行为 正确行为
CWG 170 C++98 当派生类不具有原始成员时
指向成员转换的行为不明确
予以明确
CWG 172 C++98 枚举类型提升基于其底层类型 改为基于其值范围
CWG 330
( N4261 )
C++98 double * const ( * p ) [ 3 ]
double const * const ( * p ) [ 3 ] 的转换无效
改为有效
CWG 519 C++98 空指针值转换为其他指针类型时
不保证保留
始终保留
CWG 616 C++98 对任何未初始化对象和无效值指针对象
进行左值到右值转换的行为始终未定义
允许不确定的 unsigned char
使用无效指针
由实现定义
CWG 685 C++98 若枚举类型具有固定底层类型
整型提升时未优先考虑该底层类型
优先考虑
CWG 707 C++98 整数到浮点数转换
在所有情况下都有定义行为
若被转换值超出
目标范围则行为未定义
CWG 1423 C++11 std::nullptr_t 在直接初始化和复制初始化中
均可转换为 bool
仅限直接初始化
CWG 1773 C++11 出现在潜在求值表达式中的名称表达式
即使命名对象未被odr使用仍可能在
左值到右值转换期间被求值
不予求值
CWG 1781 C++11 std::nullptr_t bool 被视为隐式转换
尽管仅对直接初始化有效
不再视为
隐式转换
CWG 1787 C++98 读取缓存在寄存器中的不确定
unsigned char 的行为未定义
改为良定义
CWG 1981 C++11 上下文转换考虑显式转换函数 不予考虑
CWG 2140 C++11 不清楚从 std::nullptr_t 左值进行
左值到右值转换是否会从内存获取这些左值
不获取
CWG 2310 C++98 对于派生类到基类指针转换和
基类到派生类成员指针转换
派生类类型可以不完整
必须完整
CWG 2484 C++20 char8_t char16_t 具有不同的整型
提升策略,但两者均可容纳
char8_t 应采用
char16_t 相同方式提升
CWG 2485 C++98 涉及位域的整型提升规范不完善 改进规范
CWG 2813 C++23 调用类纯右值的显式对象成员函数时
会发生临时物化
此情况下
不会发生
CWG 2861 C++98 指向类型不可访问对象的指针可被
转换为指向基类子对象的指针
此情况下
行为未定义
CWG 2879 C++17 临时物化转换应用于期望左值的
运算符的纯右值操作数
某些情况下不应用
CWG 2899 C++98 左值到右值转换可应用于
具有无效值表示的左值对象
此情况下
行为未定义
CWG 2901 C++98 从引用值为 - 1 int 对象的
unsigned int 左值进行左值到右值转换的结果不明确
予以明确

参见

C 文档 关于 隐式转换