Namespaces
Variants

switch statement

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
switch
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Передает управление одному из нескольких операторов в зависимости от значения условия.

Содержание

Синтаксис

attr  (необязательно) switch ( init-statement  (необязательно) condition ) statement
attr - (since C++11) любое количество attributes
init-statement - (since C++17) любой из следующих вариантов:
  • expression statement (который может быть пустым оператором ; )
  • simple declaration , обычно объявление переменной с инициализатором, но может объявлять произвольное количество переменных или structured bindings
(since C++23)

Обратите внимание, что любой init-statement должен заканчиваться точкой с запятой. Поэтому его часто неформально описывают как выражение или объявление, за которым следует точка с запятой.

condition - condition
statement - statement (обычно составной оператор)

Условие

Условием может быть либо condition , либо expression , либо simple declaration .

  • Если синтаксически это может быть разрешено как объявление structured binding , то оно интерпретируется как объявление structured binding.
(since C++26)
  • Если это может быть синтаксически разрешено как выражение, оно трактуется как выражение. В противном случае оно трактуется как объявление которое не является объявлением структурированной привязки (начиная с C++26) .

Когда управление достигает условия, условие даёт значение, которое используется для определения того, на какую метку перейдёт управление.

Выражение

Если 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 может давать только следующие типы:

  • целочисленные типы
  • перечислимые типы
  • классовые типы

Если полученное значение имеет тип класса, оно контекстно неявно преобразуется в целочисленный тип или тип перечисления.

Если (возможно преобразованный) тип подвергается integral promotions , полученное значение преобразуется в продвинутый тип.

Метки

Любое выражение внутри оператора switch может быть помечено одной или несколькими следующими метками:

attr  (необязательно) case constant-expression : (1)
attr  (необязательно) default: (2)
attr - (since C++11) любое количество атрибутов
constant-expression - преобразованное константное выражение скорректированного типа условия switch


Метка case или default связывается с самым внутренним switch оператором, который её содержит.

Если выполняется любое из следующих условий, программа является некорректной:

  • Оператор switch связан с несколькими метками case , у которых значения constant-expression совпадают после преобразований.
  • Оператор switch связан с несколькими метками default .

Передача управления потоком выполнения

Когда условие оператора switch возвращает (возможно, преобразованное) значение:

  • Если одна из связанных case констант меток имеет такое же значение, управление передается оператору, помеченному соответствующей case меткой.
  • В противном случае, если присутствует связанная default метка, управление передается оператору, помеченному default меткой.
  • В противном случае ни один из операторов в switch инструкции не будет выполнен.

case и default метки сами по себе не изменяют поток управления. Для выхода из switch оператора из середины, см. break statements .

Компиляторы могут выдавать предупреждения при проваливании (достижении следующей метки case или default без оператора break ) до тех пор, пока атрибут [[ fallthrough ]] не появится непосредственно перед меткой case для указания на преднамеренность проваливания (начиная с C++17) .

switch (1)
{
    case 1:
        std::cout << '1'; // выводит "1",
    case 2:
        std::cout << '2'; // затем выводит "2"
}
switch (1)
{
    case 1:
        std::cout << '1'; // выводит "1"
        break;            // и выходит из 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; // инициализация
        std::cout << x << '\n';
        break;
    default:
        // ошибка компиляции: переход к default:
        // приведет к входу в область видимости 'x' без его инициализации
        std::cout << "default\n";
        break;
}
switch (1)
{
    case 1:
        {
            int x = 0;
            std::cout << x << '\n';
            break;
        } // область видимости 'x' заканчивается здесь
    default:
        std::cout << "default\n"; // нет ошибки
        break;
}

Ключевые слова

switch , case , default

Пример

Следующий код демонстрирует несколько вариантов использования оператора switch :

#include <iostream>
int main()
{
    const int i = 2;
    switch (i)
    {
        case 1:
            std::cout << '1';
        case 2:              // выполнение начинается с этой метки case
            std::cout << '2';
        case 3:
            std::cout << '3';
            [[fallthrough]]; // атрибут C++17 для подавления предупреждения о сквозном выполнении
        case 5:
            std::cout << "45";
            break;           // выполнение последующих операторов прерывается
        case 6:
            std::cout << '6';
    }
    std::cout << '\n';
    switch (i)
    {
        case 4:
            std::cout << 'a';
        default:
            std::cout << 'd'; // нет подходящих константных выражений,
                              // поэтому выполняется ветка default
    }
    std::cout << '\n';
    switch (i)
    {
        case 4:
            std::cout << 'a'; // ничего не выполняется
    }
    // когда в операторе switch используются перечисления, многие компиляторы
    // выдают предупреждения, если один из перечислителей не обрабатывается
    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;
    }
    // синтаксис с инициализатором в C++17 может быть полезен, когда нет
    // неявного преобразования к целочисленному типу или типу перечисления
    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;
    }
    // патологические примеры
    // оператор не обязательно должен быть составным
    switch (0)
        std::cout << "this does nothing\n";
    // метки также не требуют составного оператора
    switch (int n = 1)
        case 0:
        case 1:
            std::cout << n << '\n';
}

Вывод:

2345
d
red
1

Отчеты о дефектах

Следующие отчеты об изменениях поведения, влияющие на дефекты, были применены задним числом к ранее опубликованным стандартам C++.

DR Applied to Behavior as published Correct behavior
CWG 1767 C++98 condition s of types that are not subject to
integral promotion could not be promoted
do not promote
condition s of these types
CWG 2629 C++98 condition could be a declaration of a floating-point variable prohibited

Смотрите также

C documentation для switch

Внешние ссылки

1. Развертка цикла с использованием устройства Даффа
2. Устройство Даффа может использоваться для реализации сопрограмм в C/C++