Оператор switch — cppreference.com
Материал из cppreference.com
Передаёт управление одному из нескольких операторов в зависимости от значения условия.
Синтаксис
атрибуты (необязательно) switch ( оператор-инициализации (необязательно) условие ) оператор
|
|||||||||
| атрибуты | — | (начиная с C++11) любое количество атрибутов |
| оператор-инициализации | — | (начиная с C++17) одно из следующего
|
| условие | — | любое из следующего:
Значение условия должно иметь целочисленный тип или тип перечисления или классовый тип, контекстуально неявно преобразуемый в целочисленный тип или тип перечисления. Если тип (возможно, преобразованный) подлежит целочисленным продвижениям, условие преобразуется в продвинутый тип. |
| оператор | — | любой оператор (обычно составной оператор). Метки case: и default: разрешены в операторе, а оператор break; имеет особое значение.
|
атрибуты (необязательно) case константное-выражение : оператор
|
(1) | ||||||||
атрибуты (необязательно) default : оператор
|
(2) | ||||||||
Объяснения
Тело оператора switch может иметь произвольное количество меток case:, если значения всех константных-выражений уникальны (после преобразований/продвижений). Может присутствовать не более одной метки default: (хотя вложенные операторы switch могут использовать свои собственные метки default: или иметь метки case:, константы которых идентичны тем, которые используются в охватывающем switch).
Если условие оценивается как значение, равное значению одного из констант-выражений, то управление передаётся оператору, помеченному этим константным-выражением.
Если условие оценивается как значение, которое не соответствует ни одной из меток case:, а метка default: присутствует, управление передаётся оператору помеченному меткой default:.
Если условие оценивается как значение, которое не соответствует ни одной из меток case:, а метка default: отсутствует, то ни один из операторов в теле switch не выполняется.
Оператор break, встречающийся в операторе, производит выход из оператора switch:
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 эквивалентен
За исключением имён, объявленных оператором инициализации (если оператор инициализации является объявлением), и имена, объявленные условием (если условие является объявлением), находятся в одной и той же области видимости, что и область видимости оператора. |
(начиная с C++17) | |||||||||||||||||||||||
Поскольку передача управления не может входить в область видимости переменной, если оператор объявления встречается внутри выражения, её область видимости должна быть определена в её собственном составном операторе:
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
#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]]; // атрибут С++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'; // нет применимых константных выражений, // поэтому выполняется значение по умолчанию } std::cout << '\n'; switch (i) { case 4: std::cout << 'a'; // ничего не выполняется } // когда перечисления используются в операторе switch, многие компиляторы выдают // предупреждения, если один из перечислителей не обрабатывается enum color { RED, GREEN, BLUE }; switch (RED) { case RED: std::cout << "красный\n"; break; case GREEN: std::cout << "зелёный\n"; break; case BLUE: std::cout << "синий\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 << "это ничего не делает\n"; // метки также не требуют составного оператора switch (int n = 1) { case 0: case 1: std::cout << n << '\n'; } }
Вывод:
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| CWG 1767 | C++98 | условия типов, которые не подлежат целочисленному продвижению, не могут быть продвинуты |
условия этих типов не продвигаются |