Difference between revisions of "cpp/language/switch"
(Added CWG #2629 DR.) |
m (Wording fix.) |
||
Line 22: | Line 22: | ||
* an {{rlp|expressions|expression}}, in this case the value of {{spar|condition}} is the value of the expression | * an {{rlp|expressions|expression}}, in this case the value of {{spar|condition}} is the value of the expression | ||
* a {{rlp|declarations|declaration}} of a single non-array variable of such type with a brace-or-equals {{rlp|initialization|initializer}}, in this case the value of {{spar|condition}} is the value of the declared variable | * a {{rlp|declarations|declaration}} of a single non-array variable of such type with a brace-or-equals {{rlp|initialization|initializer}}, in this case the value of {{spar|condition}} is the value of the declared variable | ||
− | The value of {{spar|condition}} must be of integral or enumeration type, or of a class type {{rlp|implicit conversion#Contextual conversions|contextually implicitly convertible}} to an integral or enumeration type | + | The value of {{spar|condition}} must be of integral or enumeration type, or of a class type {{rlp|implicit conversion#Contextual conversions|contextually implicitly convertible}} to an integral or enumeration type. If the (possibly converted) type is subject to {{rlp|implicit conversion#Integral promotion|integral promotions}}, {{spar|condition}} is converted to the promoted type.}} |
{{par|{{spar|statement}}|any {{rlp|statements|statement}} (typically a compound statement). {{ttb|case:}} and {{ttb|default:}} labels are permitted in {{spar|statement}} and {{c|break;}} statement has special meaning.}} | {{par|{{spar|statement}}|any {{rlp|statements|statement}} (typically a compound statement). {{ttb|case:}} and {{ttb|default:}} labels are permitted in {{spar|statement}} and {{c|break;}} statement has special meaning.}} | ||
{{par end}} | {{par end}} |
Revision as of 02:27, 21 December 2022
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:
| ||
condition | - | any of the following:
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 If init-statement is used, the switch statement is equivalent to
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:
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 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 derclaration of a floating-point variable | prohibited |
See also
C documentation for switch
|