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