switch statement - cppreference.com
Transfers control to one of several statements, depending on the value of a condition.
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:
Note that any init-statement must end with a semicolon. This is why it is often described informally as an expression or a declaration followed by a semicolon. |
| condition | - | a condition |
| statement | - | a statement (typically a compound statement) |
Condition
A condition can either be an expression or a simple declaration.
|
(since C++26) |
- If it can be syntactically resolved as an expression, it is treated as an expression. Otherwise, it is treated as a declaration that is not a structured binding declaration(since C++26).
When control reaches condition, the condition will yield a value, which is used to determine which label the control will go to.
Expression
If condition is an expression, the value it yields is the the value of the expression.
Declaration
If condition is a simple declaration, the value it yields is the value of the decision variable (see below).
Non-structured binding declaration
The declaration has the following restrictions:
- Syntactically conforms to the following form:
|
(until C++11) |
|
(since C++11) |
- The declarator cannot specify a function or an array.
- The type specifier sequence(until C++11)declaration specifier sequence can only contain type specifiers and
constexpr, and it(since C++11) cannot define a class or enumeration.
The decision variable of the declaration is the declared variable.
Type
condition can only yield the following types:
- integral types
- enumeration types
- class types
If the yielded value is of a class type, it is contextually implicitly converted to an integral or enumeration type.
If the (possibly converted) type is subject to integral promotions , the yielded value is converted to the promoted type.
Labels
Any statement within the switch statement can be labeled with one or more following labels:
attr (optional) case constant-expression :
|
(1) | ||||||||
attr (optional) default:
|
(2) | ||||||||
A case or default label is associated with the innermost switch statement enclosing it.
If any of the following conditions is satisfied, the program is ill-formed:
- A
switchstatement is associated with multiplecaselabels whose constant-expression s have the same value after conversions. - A
switchstatement is associated with multipledefaultlabels.
Control flow transfer
When the condition of a switch statement yields a (possibly converted) value:
- If one of the associated
caselabel constants has the same value, control is passed to the statement labeled by the matchedcaselabel. - Otherwise, if there is an associated
defaultlabel, control is passed to the statement labeled by thedefaultlabel. - Otherwise, none of the statements in the
switchstatement will be executed.
case and default labels in themselves do not alter the flow of control. To exit from a switch statement from the middle, see break statements.
Compilers may issue warnings on fallthrough (reaching the next case or default label without a break) unless the attribute [[fallthrough]] appears immediately before the case label to indicate that the fallthrough is intentional(since 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; }
|
||||||||||||||||||||||||
{
|
|||||||||
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.
Notes
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
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 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'; }
Output:
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 | condition s of types that are not subject to integral promotion could not be promoted |
do not promote condition s of these types |
| CWG 2629 | C++98 | condition could be a declaration of a floating-point variable | prohibited |