switch
語句
根據條件的值,將控制權轉移到若干語句之一。
目錄 |
[編輯] 語法
屬性 (可選) switch ( init-statement (可選) 條件 ) 語句 |
|||||||||
屬性 | - | (自 C++11 起) 任意數量的屬性 | ||
init-statement | - | (自 C++17 起) 以下任何一種
注意,任何 init-statement 都必須以分號結尾。這就是為什麼它通常被非正式地描述為表示式或聲明後跟分號的原因。 | ||
條件 | - | 一個條件 | ||
語句 | - | 一個語句(通常是複合語句) |
[編輯] 條件
|
(C++26 起) |
- 如果它在語法上可以解析為表示式,則將其視為表示式。否則,將其視為非結構化繫結宣告(自 C++26 起)。
當控制到達條件時,條件將產生一個值,該值用於確定控制將轉到哪個標籤。
[編輯] 表示式
如果 條件 是一個表示式,則它產生的值就是表示式的值。
[編輯] 宣告
如果 條件 是一個簡單宣告,則它產生的值是決策變數(見下文)的值。
[編輯] 非結構化繫結宣告
該宣告有以下限制:
- 語法上符合以下形式:
|
(C++11 前) |
|
(C++11 起) |
宣告的決策變數是被宣告的變數。
結構化繫結宣告該宣告有以下限制: 宣告的決策變數是由宣告引入的假定變數 e。 |
(C++26 起) |
[編輯] 型別
條件只能產生以下型別:
- 整型
- 列舉型別
- 類型別
如果產生的值是類型別,它會隱式地上下文轉換為整型或列舉型別。
如果(可能轉換後的)型別受整型提升影響,則產生的值會被轉換為提升後的型別。
[編輯] 標籤
switch 語句內的任何語句都可以帶有一個或多個以下標籤:
屬性 (可選) case 常量表達式 : |
(1) | ||||||||
屬性 (可選) default: |
(2) | ||||||||
屬性 | - | (自 C++11 起) 任意數量的屬性 |
常量表達式 | - | 一個轉換後的常量表達式,其型別為 switch 條件的調整型別。 |
一個 case 或 default 標籤與包含它的最內層 switch 語句相關聯。
如果滿足以下任何條件,程式將不正確:
- 一個 switch 語句關聯了多個 case 標籤,其 常量表達式 在轉換後具有相同的值。
- 一個 switch 語句關聯了多個 default 標籤。
[編輯] 控制流轉移
當 switch 語句的條件產生一個(可能已轉換的)值時:
- 如果其中一個關聯的 case 標籤常量具有相同的值,則控制權將傳遞給由匹配的 case 標籤標記的語句。
- 否則,如果存在關聯的 default 標籤,則控制權將傳遞給由 default 標籤標記的語句。
- 否則,switch 語句中的任何語句都不會被執行。
case 和 default 標籤本身不會改變控制流。要從 switch 語句中途退出,請參閱break 語句。
編譯器可能會對貫穿(在沒有 break 的情況下到達下一個 case 或 default 標籤)發出警告,除非屬性 [[fallthrough]]
緊接在 case 標籤之前出現,表示此貫穿是故意的(自 C++17 起)。
帶初始化器的 switch 語句如果使用 init-statement,則 switch 語句等價於
除了由 init-statement 宣告的名稱(如果 init-statement 是宣告)和由 條件 宣告的名稱(如果 條件 是宣告)位於同一作用域,該作用域也是 語句 的作用域。 |
(C++17 起) |
[編輯] 注意
由於不允許控制權進入變數的作用域,如果在 語句 內部遇到宣告語句,則必須將其置於其自己的複合語句中。
[編輯] 關鍵詞
[編輯] 示例
以下程式碼展示了 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++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 1767 | C++98 | 條件 的型別不受 整型提升 |
不提升 條件 的這些型別 |
CWG 2629 | C++98 | 條件 可以是浮點變數的宣告 | 已禁止 |
[編輯] 另請參閱
C 文件 關於 switch
|
[編輯] 外部連結
1. | 使用 Duff's Device 的迴圈展開 |
2. | Duff's device 可用於在 C/C++ 中實現協程 |