命名空间
变体
操作

表达式

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

表达式是由运算符和它们的操作数组成的序列,它指定一项计算。

表达式求值可能产生结果(例如,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_castconst_castreinterpret_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++ 程序的记号,表示嵌入在源代码中的常量值。

  • charwchar_t
  • char16_tchar32_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; // Case 1: the constituent expression of “num += 1” is “num += 1”
 
int arr2[2] = {2, 22} // Case 2: the constituent expressions
                      //         of “{2, 22}” are “2” and “22”
                      // Case 3: the constituent expressions of “= {2, 22}”
                      //         are the constituent expressions of “{2, 22}”
                      //         (i.e. also “2” and “22”)

表达式 E直接子表达式

  • E 的操作数的组成表达式,
(自 C++14 起)
  • 如果 Elambda 表达式,则按复制捕获的实体的初始化和捕获的初始化器的组成表达式,
(C++11 起)
  • E 隐式调用的任何函数调用,或
  • 如果 E 是函数调用或隐式调用函数,则调用中使用的每个默认实参的组成表达式。

表达式 E子表达式E 的直接子表达式或 E 的直接子表达式的子表达式。注意 lambda 表达式的“函数体”中出现的表达式不是 lambda 表达式的子表达式。(C++11 起)

下列表达式是完整表达式

(C++20 起)
(C++26 起)
  • 不是任何其他表达式的子表达式,并且不是任何完整表达式的其他部分的表达式

如果语言构造被定义为产生函数的隐式调用,则为了此定义的目的,语言构造的使用被认为是表达式。为了满足表达式出现的语言构造的要求而应用于表达式结果的转换也被认为是完整表达式的一部分。

对于初始化器,执行实体的初始化(包含求值聚合体的默认成员初始化器)(C++14 起)也被认为是完整表达式的一部分。

[编辑] 潜在求值表达式

除非出现以下情况,否则表达式是潜在求值的

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

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

  • typeid 运算符应用到的表达式,多态类类型的泛左值除外
  • 作为 sizeof 运算符的操作数的表达式
  • 作为 noexcept 运算符的操作数
  • 作为 decltype 说明符的操作数
(C++20 起)

除非出现以下情况,否则表达式是潜在求值的

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

潜在求值表达式是ODR 用途

[编辑] 弃值表达式

弃值表达式是仅用于其副作用的表达式。从此类表达式计算的值被丢弃。此类表达式包括任何表达式语句的完整表达式、内置逗号运算符的左侧操作数,或转型到 void 类型的转型表达式的操作数。

数组到指针和函数到指针的转换永远不应用于由弃值表达式计算的值。当且仅当表达式是volatile 限定的泛左值并具有以下形式之一时(需要内置含义,可能带圆括号),才应用左值到右值转换

  • id 表达式,
  • 数组下标表达式,
  • 类成员访问表达式,
  • 解引用,
  • 指向成员运算符,
  • 条件表达式,其中第二个和第三个操作数是这些表达式之一,
  • 逗号表达式,其中右侧操作数是这些表达式之一。

此外,如果左值是 volatile 限定的类类型,则需要 volatile 复制构造函数来初始化生成的右值临时量。

如果表达式是非 void 纯右值(在可能已发生的任何左值到右值转换之后),则会发生临时量实质化

当除转型到 void 之外的表达式丢弃声明为 [[nodiscard]] 的值时,编译器可能会发出警告。

(C++17 起)

表达式等价性

如果满足以下所有条件,则多个表达式 e1e2、...、eN表达式等价的

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

当且仅当 e1e2 是表达式等价的时,e1表达式等价于 e2(这意味着 e2 也表达式等价于 e1)。

(C++20 起)

[编辑] 缺陷报告

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

DR 应用于 已发布行为 正确行为
CWG 1054 C++98 向 volatile 变量赋值可能
由于应用于赋值结果的左值到
右值转换而导致不必要的读取
引入弃值表达式
并将此情况从列表排除
需要转换的情况
CWG 1343 C++98 聚合初始化中的析构函数调用顺序
未充分指定
聚合初始化中的完整表达式
得到良好指定
CWG 1383 C++98 左值到右值转换应用于弃值表达式
的表达式列表也涵盖了重载运算符
仅涵盖运算符
具有内置含义的运算符
具有内置含义的运算符
CWG 1576 C++11 左值到右值转换未应用于
弃值 volatile 将亡值表达式
应用转换
在这种情况下
CWG 2249 C++98 要在声明符中声明的标识符
不是 id 表达式
它们是
CWG 2431 C++11 绑定到引用的临时量的析构函数的调用
不是完整表达式
它们是

[编辑] 参见

C 文档 关于 表达式