Namespaces
Variants
Views
Actions

switch statement

From cppreference.com
< cpp‎ | language
Revision as of 08:10, 11 February 2023 by Andreas Krug (Talk | contribs)

 
 
C++ language
General topics
Flow control
Conditional execution statements
if
switch
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

Transfers control to one of several statements, depending on the value of a condition.

Contents

Syntax

attr(optional) switch ( init-statement(optional) condition ) statement
attr - (since C++11) any number of attributes
init-statement - (since C++17) any of the following:
(since C++23)
Note that any init-statement must end with a semicolon ;, which is why it is often described informally as an expression or a declaration followed by a semicolon.
condition - any of the following:
  • an expression, in this case the value of condition is the value of the expression
  • a declaration of a single non-array variable of such type with a brace-or-equals initializer, in this case the value of condition is the value of the declared variable

The value of condition must be of integral or enumeration type, or of a class type contextually implicitly convertible to an integral or enumeration type. If the (possibly converted) type is subject to integral promotions, condition is converted to the promoted type.

statement - any statement (typically a compound statement). case: and default: labels are permitted in statement and break; statement has special meaning.
attr(optional) case constant-expression : statement (1)
attr(optional) default : statement (2)
constant-expression - a constant expression of the same type as the type of condition after conversions and integral promotions

Explanation

The body of a switch statement may have an arbitrary number of case: labels, as long as the values of all constant-expressions are unique (after conversions/promotions). At most one default: label may be present (although nested switch statements may use their own default: labels or have case: labels whose constants are identical to the ones used in the enclosing switch).

If condition evaluates to a value that is equal to the value of one of constant-expressions, then control is transferred to the statement that is labeled with that constant-expression.

If condition evaluates to a value that doesn't match any of the case: labels, and the default: label is present, control is transferred to the statement labeled with the default: label.

If condition evaluates to a value that doesn't match any of the case: labels, and the default: label is not present, then none of the statements in the switch body is executed.

The break statement, when encountered in statement exits the switch statement:

switch (1)
{
    case 1:
        cout << '1'; // prints "1",
    case 2:
        cout << '2'; // then prints "2"
}
switch (1)
{
    case 1:
        cout << '1'; // prints "1"
        break;       // and exits the switch
    case 2:
        cout << '2';
        break;
}

Compilers may issue warnings on fallthrough (reaching the next case label without a break) unless the attribute [[fallthrough]] appears immediately before the case label to indicate that the fallthrough is intentional.

If init-statement is used, the switch statement is equivalent to

{
init-statement
switch ( condition ) statement

}

Except that names declared by the init-statement (if init-statement is a declaration) and names declared by condition (if condition is a declaration) are in the same scope, which is also the scope of statement.

(since C++17)

Because transfer of control is not permitted to enter the scope of a variable, if a declaration statement is encountered inside the statement, it has to be scoped in its own compound 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;
}

Keywords

switch, case, default

Example

The following code shows several usage cases of the switch statement

#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 fall through
        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';
    }
}

Output:

2345
d
red
1

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 1767 C++98 conditions of types that are not subject to
integral promotion could not be promoted
do not promote
conditions of these types
CWG 2629 C++98 condition could be a declaration of a floating-point variable prohibited

See also

C documentation for switch

External links

1.  Loop unrolling using Duff's Device
2.  Duff's device can be used to implement coroutines in C/C++