Spec-Zone.ru › C++

switch оператор

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

Синтаксис

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

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

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

Условие

condition может быть выражением или простым объявлением.

  • Если его синтаксически можно интерпретировать как объявление структурированной привязки, оно рассматривается как объявление структурированной привязки.
(начиная с 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)
  • Декларатор не может задавать функцию или массив.
  • последовательность спецификаторов типа(до C++11)последовательность спецификаторов объявления может содержать только спецификаторы типа и constexpr, а также(начиная с C++11) не может определять класс или перечисление.

Переменной выбора в объявлении является объявленная переменная.

Объявление структурированной привязки

Объявление имеет следующие ограничения:

  • expression в его инициализаторе не может иметь тип массива.
  • последовательность спецификаторов объявления может содержать только спецификаторы типа и constexpr.

Переменной выбора в объявлении является придуманная переменная e, введённая объявлением.

(начиная с C++26)

Тип

condition может выдавать значения только следующих типов:

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

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

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

Метки

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

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


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

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

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

Передача управления

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

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

Сами по себе метки case и default не изменяют поток управления. Чтобы выйти из оператора switch из его середины, см. операторы break.

Компиляторы могут выдавать предупреждения о проваливании к следующей метке (достижении следующей метки case или default без 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 могло быть объявлением переменной с плавающей точкой запрещено

См. также

Документация по C для switch

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

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

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/switch

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API