Spec-Zone.ru › C++

Оператор switch

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

Синтаксис

атрибут (необязательно) 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'; // 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;
}

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

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

{
инициализирующий оператор
switch ( условие ) оператор

}

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

(с C++17)

Поскольку передача управления не разрешена для входа в область видимости переменной, если встречается оператор объявления внутри оператора, он должен быть ограничен своим собственным составным оператором:

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 doesn't have to be a compound statement
    switch (0)
        std::cout << "this does nothing\n";
 
    // labels don't 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 условия типов, которые не подлежат
целочисленному повышению, не могли быть повышены
не повышать
условия этих типов
CWG 2629 C++98 условие могло быть объявлением переменной с плавающей точкой запрещено

См. также

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

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

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

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

Spec-Zone.ru

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