switch
statement
Передает управление одному из нескольких операторов в зависимости от значения условия.
Содержание |
Синтаксис
attr
(необязательно)
switch
(
init-statement
(необязательно)
condition
)
statement
|
|||||||||
| attr | - | (since C++11) любое количество attributes | ||
| init-statement | - |
(since C++17)
любой из следующих вариантов:
Обратите внимание, что любой init-statement должен заканчиваться точкой с запятой. Поэтому его часто неформально описывают как выражение или объявление, за которым следует точка с запятой. |
||
| condition | - | condition | ||
| statement | - | statement (обычно составной оператор) |
Условие
Условием может быть либо condition , либо expression , либо simple declaration .
|
(since C++26) |
- Если это может быть синтаксически разрешено как выражение, оно трактуется как выражение. В противном случае оно трактуется как объявление которое не является объявлением структурированной привязки (начиная с C++26) .
Когда управление достигает условия, условие даёт значение, которое используется для определения того, на какую метку перейдёт управление.
Выражение
Если condition является выражением, то возвращаемое значение - это значение данного выражения.
Объявление
Если condition является простым объявлением, возвращаемое значение - это значение переменной решения (см. ниже).
Объявление без структурированной привязки
Объявление имеет следующие ограничения:
- Синтаксически соответствует следующей форме:
|
(до C++11) |
|
(начиная с C++11) |
- Декларатор не может определять функцию или массив .
- последовательность спецификаторов типа (до C++11) последовательность спецификаторов объявления может содержать только спецификаторы типа и constexpr , и она (начиная с 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 операторы с инициализаторомЕсли используется 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: // выполнение начинается с этой метки 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++ |