switch
语句
根据条件的值,将控制权转移到多个语句中的一个。
内容 |
[编辑] 语法
attr (可选) switch ( init-statement (可选) condition ) statement |
|||||||||
attr | - | (自 C++11 起) 任意数量的 属性 | ||
init-statement | - | (自 C++17 起) 以下任何一项
请注意,任何 init-statement 都必须以分号结尾。这就是为什么它通常被非正式地描述为表达式或声明后跟分号的原因。 | ||
condition | - | 一个 条件 | ||
statement | - | 一个语句(通常是复合语句) |
[编辑] 条件
|
(自 C++26 起) |
- 如果它在语法上可以解析为表达式或声明,但不是结构化绑定声明(自 C++26 起),则将其解释为后者。
当控制权到达 condition 时,condition 将产生一个值,该值用于确定控制权将转到哪个标签。
[编辑] 表达式
如果 condition 是一个表达式,则它产生的值是该表达式的值。
[编辑] 声明
如果 condition 是一个简单声明,则它产生的值是决策变量的值(见下文)。
[编辑] 非结构化绑定声明
该声明有以下限制
- 它只有一个 声明符.
- 声明符不能指定 函数 或 数组.
- 声明符必须有 初始化器,其语法不能为 (3).
- 该 声明说明符序列 只能包含类型说明符 和 constexpr(自 C++11 起),并且不能定义 类 或 枚举.
该声明的决策变量是被声明的变量。
结构化绑定声明该声明有以下限制 该声明的决策变量是该声明 引入的 虚拟变量 e。 |
(自 C++26 起) |
[编辑] 类型
条件 只能产生以下类型
- 整型
- 枚举类型
- 类类型
如果产生的值为类类型,则会隐式地转换为整型或枚举类型。
如果(可能转换后的)类型受 整型提升 的影响,则产生的值将转换为提升后的类型。
[编辑] 标签
该 switch 语句中的任何语句都可以用以下一个或多个标签进行标记
attr (可选) case 常量表达式 : |
(1) | ||||||||
attr (可选) default: |
(2) | ||||||||
attr | - | (自 C++11 起) 任意数量的 属性 |
常量表达式 | - | switch 条件调整后的类型的 转换后的常量表达式 |
一个 case 或 default 标签与包含它的最内层 switch 语句相关联。
如果满足以下任何条件,程序将格式错误
- 一个 switch 语句与多个 case 标签相关联,这些标签的 常量表达式 s 在转换后具有相同的值。
- 一个 switch 语句与多个 default 标签相关联。
[编辑] 控制流传递
当 switch 语句的条件产生一个(可能转换后的)值时
- 如果关联的 case 标签常量之一具有相同的值,则控制将传递到由匹配的 case 标签标记的语句。
- 否则,如果存在关联的 default 标签,则控制将传递到由 default 标签标记的语句。
- 否则,switch 语句中的任何语句都不会被执行。
case 和 default 标签本身不会改变控制流。要从 switch 语句的中间退出,请参见 break 语句.
编译器可能会在穿透(到达下一个 case 或 default 标签,没有 break)时发出警告,除非属性 [[fallthrough]]
出现在 case 标签之前,表示穿透是故意的(自 C++17 起).
带有初始化器的 switch 语句如果使用了 初始化语句,则 switch 语句等效于
不同之处在于,由 初始化语句 (如果 初始化语句 是声明)声明的名称和由 条件 (如果 条件 是声明)声明的名称在同一个作用域内,该作用域也是 语句 的作用域。 |
(自 C++17 起) |
[编辑] 注释
由于控制传递 不允许进入 变量的作用域,因此如果在 语句 中遇到声明语句,则必须将其作用域限定在其自己的复合语句中
[编辑] 关键字
[编辑] 示例
以下代码展示了 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 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'; }
输出
2345 d red 1
[编辑] 缺陷报告
以下行为更改缺陷报告被追溯地应用于以前发布的 C++ 标准。
DR | 应用于 | 已发布的行为 | 正确的行为 |
---|---|---|---|
CWG 1767 | C++98 | 类型为 条件 s 的类型不受 整型提升影响的类型不能被提升 |
不提升 这些类型的 条件 s |
CWG 2629 | C++98 | 条件 可以是浮点变量的声明 | 禁止 |
[编辑] 另请参见
C 文档 for switch
|
[编辑] 外部链接
1. | 使用 Duff 设备进行循环展开 |
2. | Duff 设备可用于在 C/C++ 中实现协程 |