Namespaces
Variants

Expressions

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 + 2 的求值会生成结果 4 ),也可能产生副作用(例如, std:: printf ( "%d" , 4 ) 的求值会在标准输出上打印字符 '4' )。

每个 C++ 表达式都具有两个独立特性:类型和值类别。

目录

概述

  • 值类别 (左值、右值 、广义左值、纯右值、将亡值 (C++11 起) )按表达式的值进行分类
  • 求值顺序 规定了获取中间结果的顺序

运算符

常用运算符
赋值 自增
自减
算术 逻辑 比较 成员
访问
其他

a = b
a + = b
a - = b
a * = b
a / = b
a % = b
a & = b
a | = b
a ^ = b
a <<= b
a >>= b

++ a
-- a
a ++
a --

+ a
- a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

! a
a && b
a || b

a == b
a ! = b
a < b
a > b
a <= b
a >= b
a <=> b

a [ ... ]
* a
& a
a - > b
a. b
a - > * b
a. * b

函数调用

a ( ... )
逗号

a, b
条件

a ? b : c
特殊运算符

static_cast 将一种类型转换为另一种相关类型
dynamic_cast 在继承层次结构内进行转换
const_cast 添加或移除 cv 限定符
reinterpret_cast 将类型转换为不相关类型
C风格转换 通过混合使用 static_cast const_cast reinterpret_cast 将一种类型转换为另一种类型
new 创建具有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象并释放获取的内存区域
sizeof 查询类型的大小
sizeof... 查询 参数包 的大小 (C++11 起)
typeid 查询类型的类型信息
noexcept 检查表达式是否能抛出异常 (C++11 起)
alignof 查询类型的对齐要求 (C++11 起)

转换

内存分配

其他

主表达式

任何运算符的操作数可以是其他表达式或基本表达式(例如在 1 + 2 * 3 中,运算符+的操作数是 子表达式 2 * 3 和基本表达式 1 )。

基本表达式可以是以下任意一种:

(C++26 起)
(C++11 起)
(C++17 起)
(C++20 起)

任何括号内的表达式同样被归类为主表达式:这确保了括号具有高于任何运算符的优先级。括号会保留值、类型和值类别。

字面量

字面量是C++程序中表示嵌入源代码的常量值的标记。

  • char wchar_t
  • char16_t char32_t
(自 C++11 起)
  • char8_t
(自 C++20 起)
  • const char [ ] const wchar_t [ ]
  • const char16_t [ ] const char32_t [ ]
(自 C++11 起)
  • const char8_t [ ]
(自 C++20 起)
(C++11 起)

完整表达式

一个 组成表达式 的定义如下:

  • 表达式的构成表达式就是该表达式本身。
  • 花括号包围的初始化列表 或(可能带括号的)表达式列表的构成表达式,是相应列表中各元素的构成表达式。
  • = 开头的 初始化器 的构成表达式,是 初始化子句 的构成表达式。
int num1 = 0;
num1 += 1; // 情况1:“num += 1”的构成表达式是“num += 1”
int arr2[2] = {2, 22} // 情况2:“{2, 22}”的构成表达式是“2”和“22”
                      // 情况3:“= {2, 22}”的构成表达式是“{2, 22}”的构成表达式
                      //         (即同样是“2”和“22”)

表达式 E 直接子表达式 是指

  • E 操作数的组成表达式,
(C++14 起)
  • E lambda 表达式 ,则按副本捕获的实体的初始化及各捕获项初始化器的组成表达式,
(C++11 起)
  • 任何由 E 隐式调用的函数调用,或
  • E 是函数调用或隐式调用函数,则调用中使用的每个 默认实参 的组成表达式。

表达式的 子表达式 是指该表达式的直接子表达式,或其直接子表达式的子表达式。 注意:出现在 lambda 表达式“函数体”中的表达式不属于该 lambda 表达式的子表达式。 (since C++11)

以下表达式为 完整表达式 

(since C++20)
(since C++26)
  • 不属于任何其他表达式的子表达式且不构成任何完整表达式一部分的表达式

如果某个语言结构被定义为产生对函数的隐式调用,那么该语言结构的使用就本定义而言被视为一个表达式。为满足表达式所在语言结构的要求而对表达式结果应用的转换,也被视为完整表达式的一部分。

对于初始化器而言,执行实体的初始化 (包括对聚合体的默认成员初始化器进行求值) (since C++14) 同样被视为完整表达式的一部分。

可能求值表达式

表达式是 潜在求值 的,除非

  • 它是 sizeof 运算符的操作数,或
  • 它是 typeid 运算符的操作数且不指代 多态 类类型的左值。
(C++11 前)

下列操作数是 不求值操作数 ,它们不会被求值:

(C++20 起)

表达式是 潜在求值 的,除非

  • 它是一个不求值操作数,或
  • 它是一个不求值操作数的子表达式。
(C++11 起)

可能被求值的表达式属于 ODR-use

被丢弃值表达式

一个 弃值表达式 是仅为其副作用而使用的表达式。此类表达式计算出的值会被丢弃。这类表达式包括:任何 表达式语句 的完整表达式、内置逗号运算符的左操作数,或强制转换为 void 类型的强制转换表达式的操作数。

数组到指针和函数到指针的转换永远不会应用于被弃值表达式计算的结果。当且仅当表达式是 volatile限定 的泛左值且满足以下形式之一时(要求具有内置含义,可包含括号),才会进行左值到右值的转换:

  • id表达式,
  • 数组下标表达式,
  • 类成员访问表达式,
  • 间接寻址,
  • 指向成员操作,
  • 条件表达式(其中第二和第三操作数均为上述表达式之一),
  • 逗号表达式(其中右操作数为上述表达式之一)。

此外,如果左值是volatile限定类类型,则需要使用volatile拷贝构造函数来初始化生成的右值临时对象。

若表达式为非 void 纯右值(在可能发生的任何左值到右值转换后),将发生 临时物化

当非强制转换为 void 的表达式丢弃被声明为 [[ nodiscard ]] 的值时,编译器可能发出警告。

(since C++17)

表达式等价性

若满足下列所有条件,则称一系列表达式 e1 , e2 , ..., eN 具有 表达式等价性

  1. 它们具有相同的效果。
  2. 它们要么都是 常量子表达式 ,要么都不是。
  3. 它们要么都是 noexcept ,要么都不是。

当且仅当 e1 e2 具有表达式等价性时,称 e1 表达式等价于 e2 (这意味着 e2 也表达式等价于 e1 )。

(since C++20)

缺陷报告

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

缺陷报告 适用标准 发布时行为 正确行为
CWG 1054 C++98 对volatile变量赋值可能因对赋值结果应用左值到右值转换而导致不必要的读取操作 引入弃值表达式并将此情形从需要该转换的情况列表中排除
CWG 1343 C++98 聚合初始化中析构函数调用顺序的规定不够明确 明确定义了聚合初始化中的完整表达式
CWG 1383 C++98 对弃值表达式应用左值到右值转换的表达式列表也包含重载运算符 仅涵盖具有内置含义的运算符
CWG 1576 C++11 未对弃值的volatile xvalue表达式应用左值到右值转换 在此情况下应用该转换
CWG 2249 C++98 声明符中要声明的标识符不是id表达式 它们是id表达式
CWG 2431 C++11 绑定到引用的临时对象析构函数的调用不是完整表达式 它们是完整表达式

参见

C 文档 关于 表达式