命名空間
變體
動作

switch 敘述

出自 cppreference.com
< cpp‎ | language
 
 
C++ 語言
一般主題
流程控制
條件執行陳述式
if
switch
疊代陳述式 (迴圈)
for
範圍 for (C++11)
跳躍陳述式
函式
函式宣告
Lambda 函式運算式
inline 指定符
動態例外規範 (直到 C++17*)
noexcept 指定符 (C++11)
例外
命名空間
型別
指定符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
儲存期指定符
初始化
 
 

根據條件的值,將控制權轉移到多個敘述之一。

目錄

[編輯] 語法

attr (可選) switch ( init-statement (可選) condition ) statement
屬性 - (C++11 起) 任意數量的 屬性 (attributes)
初始化陳述式 (init-statement) - (自 C++17 起) 以下任一項
(自 C++23 起)

請注意,任何 init-statement 都必須以分號結尾。這就是為什麼它通常被非正式地描述為一個表達式或宣告,後面跟著一個分號。

條件 (condition) - 一個 條件
statement - 一個敘述(通常為複合敘述)

[編輯] 條件

condition 可以是 表達式簡單宣告

  • 如果它在語法上可以被解析為 結構化綁定 宣告,則將其解釋為結構化綁定宣告。
(C++26 起)
  • 如果它在語法上可以被解析為表達式,則將其視為表達式。否則,將其視為宣告(非結構化綁定宣告)(C++26 起)

當控制到達 condition 時,條件會產生一個值,該值用於決定控制權將轉向哪個標籤。

[編輯] 表達式

如果 condition 是一個表達式,它產生的值即為該表達式的值。

[編輯] 宣告

如果 condition 是一個簡單宣告,它產生的值即為決策變數的值(見下文)。

[編輯] 非結構化綁定宣告

該宣告具有以下限制

  • 語法上符合以下形式
  • type-specifier-seq declarator = assignment-expression
(直到 C++11)
  • attribute-specifier-seq(可選) decl-specifier-seq declarator brace-or-equal-initializer
(C++11 起)

該宣告的決策變數就是宣告出的變數。

結構化綁定宣告

該宣告具有以下限制

該宣告的決策變數是由該宣告所引入的創造變數 e

(C++26 起)

[編輯] 類型

condition 只能產生以下類型

  • 整數類型
  • 列舉類型
  • 類別類型

如果產生的值屬於類別類型,它會在語境中隱式轉換為整數或列舉類型。

如果(可能經過轉換後的)類型適用於整數提升,則產生的值會轉換為提升後的類型。

[編輯] 標籤

switch 敘述中的任何敘述都可以使用以下一個或多個標籤進行標記

attr (可選) case constant-expression : (1)
attr (可選) default: (2)
屬性 - (C++11 起) 任意數量的 屬性 (attributes)
constant-expression - switch 條件調整後類型的轉換後常數表達式


casedefault 標籤會與包圍它的最內層 switch 敘述相關聯。

若滿足以下任一條件,程式即為格式錯誤 (ill-formed):

  • 一個 switch 敘述不能與多個轉換後具有相同值的 constant-expression case 標籤相關聯。
  • 一個 switch 敘述不能與多個 default 標籤相關聯。

[編輯] 控制流轉移

switch 敘述的條件產生一個(可能經過轉換的)值時

  • 如果其中一個關聯的 case 標籤常數具有相同的值,則控制權會傳遞到由該匹配的 case 標籤標記的敘述。
  • 否則,如果存在關聯的 default 標籤,則控制權會傳遞到由 default 標籤標記的敘述。
  • 否則,switch 敘述中的任何敘述都不會被執行。

casedefault 標籤本身不會改變控制流。要從 switch 敘述的中間退出,請參閱 break 敘述

編譯器可能會對貫穿(fallthrough,即到達下一個 casedefault 標籤而沒有 break)發出警告,除非在 case 標籤之前緊接出現屬性 [[fallthrough]],以表示貫穿是故意的(自 C++17 起)

switch (1)
{
    case 1:
        std::cout << '1'; // prints "1",
    case 2:
        std::cout << '2'; // then prints "2"
}
switch (1)
{
    case 1:
        std::cout << '1'; // prints "1"
        break;            // and exits the switch
    case 2:
        std::cout << '2';
        break;
}

帶有初始化器的 switch 敘述

如果使用了 init-statement,則 switch 敘述等同於

{
初始化陳述式 (init-statement)
switch ( condition ) statement

}

唯一的區別是由 init-statement 宣告的名稱(如果 init-statement 是一個宣告)和由 condition 宣告的名稱(如果 condition 是一個宣告)位於同一個作用域中,該作用域也是 statement 的作用域。

(自 C++17 起)

[編輯] 筆記

由於不允許控制轉移進入變數的作用域,如果在 statement 內部遇到宣告敘述,則必須將其限定在自己的複合敘述中

switch (1)
{
    case 1:
        int x = 0; // initialization
        std::cout << x << '\n';
        break;
    default:
        // compilation error: jump to default:
        // would enter the scope of 'x' without initializing it
        std::cout << "default\n";
        break;
}
switch (1)
{
    case 1:
        {
            int x = 0;
            std::cout << x << '\n';
            break;
        } // scope of 'x' ends here
    default:
        std::cout << "default\n"; // no error
        break;
}

[編輯] 關鍵字

switch, case, default

[編輯] 範例

以下程式碼展示了 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 可以是浮點變數的宣告 禁止

[編輯] 參閱

switchC 語言文件

[編輯] 外部連結

1.  使用 Duff's Device 的迴圈展開
2.  Duff's device 可用於在 C/C++ 中實現協程 (coroutine)
English Deutsch 日本語 中文(简体) 中文(繁體)