運算式
運算式是運算子 (operators) 及其運算元 (operands) 的序列,用以指定一個計算。
運算式求值可能會產生結果(例如:對 2 + 2 求值會得到結果 4),也可能會產生副作用(例如:對 std::printf("%d", 4) 求值會將字元 '4' 列印至標準輸出)。
每個 C++ 運算式都有兩個獨立的屬性:類型 (type) 與值類別 (value category)。
目錄 |
[編輯] 概覽
[編輯] 運算子
| 常用運算子 | ||||||
|---|---|---|---|---|---|---|
| 賦值 | 遞增 遞減 |
算術 | 邏輯 | 比較 | 成員 存取 |
其他 |
|
a = b |
++a |
+a |
!a |
a == b |
a[...] |
函數呼叫 a(...) |
| 逗號 a, b | ||||||
| 條件 a ? b : c | ||||||
| 特殊運算子 | ||||||
|
static_cast 將一種類型轉換為另一種相關類型 | ||||||
[編輯] 轉換
- 標準轉換 從一種型別到另一種型別的隱式轉換
-
const_cast轉換 -
static_cast轉換 -
dynamic_cast轉換 -
reinterpret_cast轉換 - 顯式轉換 (explicit cast) 使用 C 風格轉換標記法與函式風格標記法的轉換
- 使用者自定義轉換 使得可以指定從使用者定義類別進行的轉換
[編輯] 記憶體配置
- new 運算式 動態配置記憶體
- delete 運算式 動態釋放記憶體
[編輯] 其他
[編輯] 主要運算式
任何運算子的運算元可以是其他運算式或主要運算式(例如在 1 + 2 * 3 中,operator+ 的運算元為子運算式 2 * 3 與主要運算式 1)。
主要運算式包括以下任何一項:
-
this - 字面量(例如 2 或 "Hello, world")
- 識別符運算式,包括:
- 適當宣告的 非限定識別符(例如 n 或 cout),
- 適當宣告的 限定識別符(例如 std::string::npos),以及
- 將在 宣告子 中宣告的識別符
| (C++26 起) |
| (C++11 起) | |
| (自 C++17 起) | |
| (自 C++20 起) |
任何括號中的運算式亦被歸類為主要運算式:這保證了括號具有高於任何運算子的優先級。括號會保留值、型別與值類別。
[編輯] 字面量
字面量是 C++ 程式中代表原始程式碼中嵌入的常量值的語彙單元 (tokens)。
- char 或 wchar_t
|
(C++11 起) |
|
(自 C++20 起) |
- const char[] 或 const wchar_t[]
|
(C++11 起) |
|
(自 C++20 起) |
- 布林字面量 為型別 bool 的值,即 true 與 false
| (C++11 起) |
[編輯] 完整運算式
組成運算式 (constituent expression) 定義如下:
- 一個運算式的組成運算式即為該運算式本身。
- 大括號括起的初始化列表或(可能帶括號的)運算式列表的組成運算式,是該列表各元素的組成運算式。
- 以
=開頭的 初始化器 的組成運算式,是該 initializer-clause 的組成運算式。
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 的 直接子運算式 (immediate subexpressions) 為:
- E 之運算元的組成運算式,
| (C++14 起) | |
|
(C++11 起) |
- E 隱式呼叫的任何函式呼叫,或
- 若 E 為函式呼叫或隱式呼叫函式,則為呼叫中所使用的每個 預設引數 的組成運算式。
運算式 E 的 子運算式 (subexpression) 為 E 的直接子運算式,或是 E 的直接子運算式的子運算式。注意,出現在 lambda 運算式「函式體」中的運算式並非該 lambda 運算式的子運算式。(C++11 起)
以下運算式為 完整運算式 (full-expressions):
| (自 C++20 起) |
| (C++26 起) |
- 不屬於任何其他運算式的子運算式,且未作為任何完整運算式一部分的運算式
若語言構造被定義為產生對函式的隱式呼叫,則該語言構造的使用就本定義而言被視為一個運算式。為了滿足出現該運算式的語言構造的要求,而應用於運算結果的轉換也被視為完整運算式的一部分。
對於初始化器,執行實體的初始化 (包括對聚合的預設成員初始化器求值)(C++14 起) 也被視為完整運算式的一部分。
[編輯] 潛在求值運算式
|
運算式為 潛在求值 (potentially evaluated),除非: |
(直到 C++11) | ||
|
以下運算元為 未求值運算元 (unevaluated operands),它們不會被求值:
運算式為 潛在求值 (potentially evaluated),除非:
|
(C++11 起) |
潛在求值運算式屬於 ODR-use。
| 本節尚不完整 原因:未求值運算元的範例 |
[編輯] 丟棄值運算式
丟棄值運算式 (discarded-value expression) 是指僅因其副作用而使用的運算式。從這類運算式計算出的值會被丟棄。此類運算式包括任何 運算式語句 的完整運算式、內建逗號運算子的左運算元,或轉換為 void 型別的轉型運算式的運算元。
陣列轉指標與函式轉指標的轉換永遠不會應用於丟棄值運算式所計算的值。僅當運算式為 volatile 限定 的 glvalue 且具有以下形式之一(需為內建含義,可能帶括號)時,才會應用 lvalue 轉 rvalue 的轉換:
- 識別符運算式 (id-expression),
- 陣列下標運算式,
- 類別成員存取運算式,
- 間接運算 (indirection),
- 指向成員指標運算,
- 第二與第三運算元皆為上述運算式之一的條件運算式,
- 右運算元為上述運算式之一的逗號運算式。
此外,若該 lvalue 為 volatile 限定的類別型別,則需要一個 volatile 複製建構函式來初始化所得的 rvalue 臨時物件。
|
若該運算式為非 void 的 prvalue(在經過任何可能發生的 lvalue 轉 rvalue 轉換後),則會發生 臨時物件具現化 (temporary materialization)。 當表達式(轉換為 void 者除外)丟棄宣告為 |
(自 C++17 起) |
運算式等價性若滿足以下所有條件,則多個運算式 e1, e2, ..., eN 為 運算式等價 (expression-equivalent): 若且唯若 e1 與 e2 為運算式等價時(這意味著 e2 也與 e1 運算式等價),則稱 e1 運算式等價於 e2。 |
(自 C++20 起) |
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。
| DR | 應用於 | 出版時的行為 | 正確的行為 |
|---|---|---|---|
| CWG 1054 | C++98 | 賦值給 volatile 變數可能會 導致因 lvalue 轉 rvalue 轉換應用於賦值結果而產生不必要的讀取 |
引入丟棄值運算式 並將此情況從 需要該轉換的情況清單中排除 |
| CWG 1343 | C++98 | 聚合初始化中解構函式呼叫的 定序說明不足 |
聚合初始化中的完整運算式 已明確定義 |
| CWG 1383 | C++98 | 將 lvalue 轉 rvalue 轉換應用於 丟棄值運算式的運算式清單 也涵蓋了重載運算子 |
僅涵蓋 具有內建含義的運算子 |
| CWG 1576 | C++11 | lvalue 轉 rvalue 轉換未應用於 丟棄值 volatile xvalue 運算式 |
應用此轉換 在此情況下 |
| CWG 2249 | C++98 | 將在宣告子中宣告的識別符 並非識別符運算式 |
它們是 |
| CWG 2431 | C++11 | 綁定到參考的臨時物件的 解構函式呼叫不是完整運算式 |
它們是 |
[編輯] 參見
| C 語言文件 關於 運算式 的內容
|