switch 敘述
根據條件的值,將控制權轉移到多個敘述之一。
目錄 |
[編輯] 語法
attr (可選) switch ( init-statement (可選) condition ) statement |
|||||||||
| 屬性 | - | (C++11 起) 任意數量的 屬性 (attributes) | ||
| 初始化陳述式 (init-statement) | - | (自 C++17 起) 以下任一項
請注意,任何 init-statement 都必須以分號結尾。這就是為什麼它通常被非正式地描述為一個表達式或宣告,後面跟著一個分號。 | ||
| 條件 (condition) | - | 一個 條件 | ||
| statement | - | 一個敘述(通常為複合敘述) |
[編輯] 條件
|
(C++26 起) |
- 如果它在語法上可以被解析為表達式,則將其視為表達式。否則,將其視為宣告(非結構化綁定宣告)(C++26 起)。
當控制到達 condition 時,條件會產生一個值,該值用於決定控制權將轉向哪個標籤。
[編輯] 表達式
如果 condition 是一個表達式,它產生的值即為該表達式的值。
[編輯] 宣告
如果 condition 是一個簡單宣告,它產生的值即為決策變數的值(見下文)。
[編輯] 非結構化綁定宣告
該宣告具有以下限制
- 語法上符合以下形式
|
(直到 C++11) |
|
(C++11 起) |
- 宣告子 (declarator) 不能指定 函式 或 陣列。
- 型別說明符序列(C++11 前)宣告說明符序列 只能包含型別說明符和 constexpr,並且它(C++11 起) 不能定義 類別 或 列舉。
該宣告的決策變數就是宣告出的變數。
結構化綁定宣告該宣告具有以下限制 該宣告的決策變數是由該宣告所引入的創造變數 e。 |
(C++26 起) |
[編輯] 類型
condition 只能產生以下類型
- 整數類型
- 列舉類型
- 類別類型
如果產生的值屬於類別類型,它會在語境中隱式轉換為整數或列舉類型。
如果(可能經過轉換後的)類型適用於整數提升,則產生的值會轉換為提升後的類型。
[編輯] 標籤
switch 敘述中的任何敘述都可以使用以下一個或多個標籤進行標記
attr (可選) case constant-expression : |
(1) | ||||||||
attr (可選) default: |
(2) | ||||||||
| 屬性 | - | (C++11 起) 任意數量的 屬性 (attributes) |
| constant-expression | - | switch 條件調整後類型的轉換後常數表達式 |
case 或 default 標籤會與包圍它的最內層 switch 敘述相關聯。
若滿足以下任一條件,程式即為格式錯誤 (ill-formed):
- 一個 switch 敘述不能與多個轉換後具有相同值的 constant-expression case 標籤相關聯。
- 一個 switch 敘述不能與多個 default 標籤相關聯。
[編輯] 控制流轉移
當 switch 敘述的條件產生一個(可能經過轉換的)值時
- 如果其中一個關聯的 case 標籤常數具有相同的值,則控制權會傳遞到由該匹配的 case 標籤標記的敘述。
- 否則,如果存在關聯的 default 標籤,則控制權會傳遞到由 default 標籤標記的敘述。
- 否則,switch 敘述中的任何敘述都不會被執行。
case 和 default 標籤本身不會改變控制流。要從 switch 敘述的中間退出,請參閱 break 敘述。
編譯器可能會對貫穿(fallthrough,即到達下一個 case 或 default 標籤而沒有 break)發出警告,除非在 case 標籤之前緊接出現屬性 [[fallthrough]],以表示貫穿是故意的(自 C++17 起)。
|
帶有初始化器的 switch 敘述如果使用了 init-statement,則 switch 敘述等同於
唯一的區別是由 init-statement 宣告的名稱(如果 init-statement 是一個宣告)和由 condition 宣告的名稱(如果 condition 是一個宣告)位於同一個作用域中,該作用域也是 statement 的作用域。 |
(自 C++17 起) | |||||||||||||||||||||||
[編輯] 筆記
由於不允許控制轉移進入變數的作用域,如果在 statement 內部遇到宣告敘述,則必須將其限定在自己的複合敘述中
[編輯] 關鍵字
[編輯] 範例
以下程式碼展示了 switch 敘述的幾種用法
#include <iostream> int main() { const int i = 2; switch (i) { case 1: std::cout << '1'; case 2: // execution starts at this case label std::cout << '2'; case 3: std::cout << '3'; [[fallthrough]]; // C++17 attribute to silent the warning on fallthrough case 5: std::cout << "45"; break; // execution of subsequent statements is terminated case 6: std::cout << '6'; } std::cout << '\n'; switch (i) { case 4: std::cout << 'a'; default: std::cout << 'd'; // there are no applicable constant expressions // therefore default is executed } std::cout << '\n'; switch (i) { case 4: std::cout << 'a'; // nothing is executed } // when enumerations are used in a switch statement, many compilers // issue warnings if one of the enumerators is not handled enum color { RED, GREEN, BLUE }; switch (RED) { case RED: std::cout << "red\n"; break; case GREEN: std::cout << "green\n"; break; case BLUE: std::cout << "blue\n"; break; } // the C++17 init-statement syntax can be helpful when there is // no implicit conversion to integral or enumeration type struct Device { enum State { SLEEP, READY, BAD }; auto state() const { return m_state; } /* ... */ private: State m_state{}; }; switch (auto dev = Device{}; dev.state()) { case Device::SLEEP: /* ... */ break; case Device::READY: /* ... */ break; case Device::BAD: /* ... */ break; } // pathological examples // the statement does not have to be a compound statement switch (0) std::cout << "this does nothing\n"; // labels do not require a compound statement either switch (int n = 1) case 0: case 1: std::cout << n << '\n'; }
輸出
2345 d red 1
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。
| DR | 應用於 | 出版時的行為 | 正確的行為 |
|---|---|---|---|
| CWG 1767 | C++98 | 不適用於整數提升的類型之 condition 無法進行提升 |
不進行提升 這些類型的 condition |
| CWG 2629 | C++98 | condition 可以是浮點變數的宣告 | 禁止 |
[編輯] 參閱
| switch 的 C 語言文件
|
[編輯] 外部連結
| 1. | 使用 Duff's Device 的迴圈展開 |
| 2. | Duff's device 可用於在 C/C++ 中實現協程 (coroutine) |