表达式
表達式是運算符 和操作數 的序列,它指定一項計算。
表達式的求值可以產生一個結果(比如 2 + 2 的求值產生結果 4),也可能產生副作用(比如對 std::printf("%d", 4) 的求值在標準輸出上列印字符 '4')。
每個 C++ 表達式均被描述為具有兩種獨立的性質:類型和值類別。
概述
運算符
| 常見運算符 | ||||||
|---|---|---|---|---|---|---|
| 賦值 | 自增/自減 | 算術 | 邏輯 | 比較 | 成員訪問 | 其他 |
|
|
|
|
|
|
|
函數調用a(...)
|
逗號a, b
| ||||||
條件a ? b : c
| ||||||
| 特殊運算符 | ||||||
|
static_cast 轉換一個類型為另一相關類型 | ||||||
轉換
- 標準轉換是從一個類型到另一類型的隱式轉換
const_cast轉換static_cast轉換dynamic_cast轉換reinterpret_cast轉換- 顯式類型轉換,可使用 C 風格寫法和函數風格寫法
- 用戶定義轉換使得可以指定源自用戶定義類的轉換
內存分配
- new 表達式動態地分配內存
- delete 表達式動態地解分配內存
其他
初等表達式
任何運算符的操作數都可以是其他的表達式或初等表達式(例如,1 + 2 * 3 中 operator+ 的操作數是子表達式 2 * 3 和初等表達式 1)。
初等表達式包括以下各項:
this- 字面量(例如
2或"Hello, world") - 標識表達式,包括
| (C++26 起) |
| (C++11 起) | |
| (C++17 起) | |
| (C++20 起) | |
| (C++26 起) |
任何帶括號表達式也被歸類為初等表達式:這確保了括號具有比任何運算符更高的優先級。括號保持值、類型和值類別不變。
字面量
字面量是 C++ 程序中用以表現嵌入到原始碼中的常量值的記號。
char或wchar_t
|
(C++11 起) |
|
(C++20 起) |
const char[]或const wchar_t[]
|
(C++11 起) |
|
(C++20 起) |
- 布爾字面量是
bool類型的值,即true和false
| (C++11 起) |
完整表達式
下列表達式是完整表達式 :
| (C++20 起) |
|
(C++26 起) |
- 不作為任何其他表達式的子表達式,也不屬於任何完整表達式的表達式
如果某個語言構造被定義為會產生對函數的隱式調用,那麼對該語言構造的使用在此定義下就被視為一個表達式。為了滿足該表達式所在語言構造的要求而對其結果應用的轉換,也被視為完整表達式的一部分。
對於初始化器,對實體進行初始化(包括對聚合體的默認成員初始化器求值)(C++14 起)也被視為完整表達式的一部分。
表達式 E 的子表達式 是 E 的立即子表達式 或 E 的立即子表達式 的子表達式。注意在 lambda 表達式的「函數體」中出現的表達式不是該 lambda 表達式的子表達式。(C++11 起)
表達式 E 的立即子表達式 是:
E的各操作數的成分表達式,
| (C++14 起) | |
|
(C++11 起) |
E隱式調用的函數調用,或E是函數調用或隱式調用了函數時,該調用中用到的每個默認實參的成分表達式。
成分表達式 的定義如下:
- 表達式的成分表達式是該表達式自身。
- 花括號包圍的初始化器列表或(可能帶括號的)表達式列表的成分表達式是對應列表中所有元素的成分表達式。
- 以
=開頭的初始化器的成分表達式是初始化器子句 的成分表達式。
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”)
潛在求值表達式
|
除了以下表達式,其他表達式都潛在求值: |
(C++11 前) | ||||
|
以下操作數是不求值操作數,它們不會被求值:
除了以下表達式,其他表達式都潛在求值:
|
(C++11 起) |
潛在求值表達式被ODR 使用。
| 本節未完成 原因:不求值操作數相關的示例 |
棄值表達式
棄值表達式 是只用來實施它的副作用的表達式。從這種表達式計算的值會被捨棄。這樣的表達式包括任何表達式語句的完整表達式,內建逗號運算符的左邊的實參,以及轉換到類型 void 的類型轉換表達式的實參。
棄值表達式的計算結果永遠不會進行數組到指針和函數到指針轉換。只有在該表達式是 有 volatile 限定的左值(C++11 前)泛左值(C++11 起),並具有下列形式之一(必須為它的內建含義,可以有括號)時才會進行左值到右值轉換:
- 標識表達式(id-expression)
- 數組下標表達式
| (C++26 起) |
- 類成員訪問表達式
- 間接尋址
- 成員指針操作
- 條件表達式,它的第二個和第三個操作數都是這些表達式中的一種
- 逗號表達式,它的右操作數是這些表達式中的一種。
此外,如果該左值擁有具有 volatile 限定的類類型,那麼要求用 volatile 複製構造函數來初始化作為結果的右值臨時量。
|
如果表達式(經過可能會發生的任何左值向右值轉換之後)是非 當表達式丟棄了聲明為 |
(C++17 起) |
表達式等價若干表達式 若且唯若 |
(C++20 起) |
缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
| 缺陷報告 | 應用於 | 出版時的行為 | 正確行為 |
|---|---|---|---|
| CWG 1054 | C++98 | 為 volatile 變量賦值可能會由於需要對賦值結果 進行左值到右值轉換而產生不必要的讀操作 |
引入棄值表達式並將該情況排除在 需要進行該轉換的情況之外 |
| CWG 1343 | C++98 | 聚合初始化中析構函數調用的順序尚未指定 | 正確指定了聚合初始化中的完整表達式 |
| CWG 1383 | C++98 | 棄值表達式中會應用左值到右值轉換的表達式列表也覆蓋了重載的運算符 | 只覆蓋內建運算符 |
| CWG 1576 | C++11 | 不會對棄值 volatile 亡值表達式應用左值到右值轉換 | 此時會應用該轉換 |
| CWG 2249 | C++98 | 在聲明符中將要聲明的標識符不是標識表達式 | 是標識表達式 |
| CWG 2431 | C++11 | 對綁定到引用的臨時量的析構函數的調用不是完整表達式 | 是完整表達式 |
參閱
表達式的 C 文檔
|