Пространства имён
Варианты
Действия

Оператор switch

Материал из cppreference.com
< cpp‎ | language
 
 
 
Инструкции
Метки
метка : оператор
Операторы выражений
выражение ;
Составные операторы
{ оператор... }
Операторы выбора
if
switch
Операторы итерирования
while
do-while
for
диапазонный for(C++11)
Операторы переходов
break
continue
return
goto
Операторы объявления
объявление ;
Блоки try
try составной-оператор последовательность-обработчиков
Транзакционная память
synchronized, atomic_commit, и т.д. (ТС TM)
 

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

Содержание

[править] Синтаксис

атрибуты (необязательно) switch ( оператор-инициализации (необязательно) условие ) оператор
атрибуты (начиная с C++11) любое количество атрибутов
оператор-инициализации (начиная с C++17) одно из следующего
(начиная с C++23)
Обратите внимание, что любой оператор инициализации должен заканчиваться точкой с запятой ;, поэтому его часто неофициально описывают как выражение или объявление, за которым следует точка с запятой.


условие любое из следующего:
  • выражение, в этом случае значением условия является значение выражения
  • объявление одной переменной, не являющейся массивом, такого типа с инициализатором в виде фигурных скобок или равенства, в этом случае значением условия является значением объявленной переменной

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

оператор любой оператор (��бычно составной оператор). Метки 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;
}

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

Если используется оператор-инициализации, оператор switch эквивалентен

{
оператор-инициализации
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, 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]]; // атрибут С++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';
    }
}

Вывод:

2345
d
красный
1

[править] Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 1767 C++98 условия типов, которые не подлежат целочисленному
продвижению, не могут быть продвинуты
условия этих типов не продвигаются

[править] Смотрите также

[править] Внешние ссылки

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