switch
statement
根据条件表达式的值,将控制权转移至多个语句中的某一个。
目录 |
语法
attr
(可选)
switch
(
init-statement
(可选)
condition
)
statement
|
|||||||||
| attr | - | (C++11 起) 任意数量的 属性 | ||
| init-statement | - |
(C++17 起)
以下任意一项:
注意:任何 init-statement 必须以分号结尾。因此常被非正式地描述为表达式或声明后接分号。 |
||
| condition | - | 一个 条件 | ||
| statement | - | 一条语句(通常是复合语句) |
条件表达式
|
(since C++26) |
- 如果它能被语法解析为表达式,则被视为表达式。否则,它被视为声明 (非结构化绑定声明 (自 C++26 起) 。
当控制流到达条件语句时,该条件将产生一个值,该值用于确定控制流将转向哪个标签。
表达式
如果 condition 是一个表达式,其产生的值即为该表达式的值。
声明
如果 condition 是一个简单声明,其产生的值即为决策变量的值(详见下文)。
非结构化绑定声明
该声明具有以下限制:
- 语法上符合以下形式:
|
(C++11 前) |
|
(C++11 起) |
声明的决策变量即为所声明的变量。
结构化绑定声明该声明具有以下限制: 该声明的决策变量是由 声明引入的 虚构变量 e 。 |
(自 C++26 起) |
类型
condition 仅可生成以下类型:
- 整型
- 枚举类型
- 类类型
如果产生的值是类类型,则会在上下文中隐式转换为整数或枚举类型。
如果(可能转换后的)类型适用于 整型提升 ,则产生的值将转换为提升后的类型。
标签
在 switch 语句内的任何语句都可以使用以下一种或多种标签进行标注:
attr
(可选)
case
constant-expression
:
|
(1) | ||||||||
attr
(可选)
default:
|
(2) | ||||||||
| attr | - | (since C++11) 任意数量的 属性 |
| constant-expression | - | 符合 switch 条件调整后类型的 转换后常量表达式 |
一个
case
或
default
标签与其最内层包围它的
switch
语句相关联。
若满足以下任一条件,则程序非良构:
- 一个 switch 语句关联了多个 case 标签,这些标签的 常量表达式 在转换后具有相同的值。
- 一个 switch 语句关联了多个 default 标签。
控制流转移
当 switch 语句的条件产生一个(可能经过转换的)值时:
- 如果某个关联的 case 标签常量具有相同值,控制权将传递给由匹配的 case 标签标记的语句。
- 否则,如果存在关联的 default 标签,控制权将传递给由 default 标签标记的语句。
- 否则, switch 语句中的所有语句都不会被执行。
case 和 default 标签本身不会改变控制流。要从 switch 语句中间退出,请参阅 break 语句 。
编译器可能会对直落(在没有
break
的情况下进入下一个
case
或
default
标签)发出警告
,除非紧邻
case
标签前出现
[[
fallthrough
]]
属性以表明该直落行为是预期的
(C++17 起)
。
|
带初始化器的 switch 语句若使用 初始化语句 ,则 switch 语句等价于
不同之处在于:由 初始化语句 (若 初始化语句 是声明)声明的名称,以及由 条件 (若 条件 是声明)声明的名称处于同一作用域,该作用域也是 语句 的作用域。 |
(C++17 起) | |||||||||||||||||||||||
注释
由于控制流 不允许跳转至变量作用域内 ,如果在 语句 内部遇到声明语句,该声明必须被限定在自身的复合语句作用域中:
关键词
示例
以下代码展示了 switch 语句的几种使用场景:
#include <iostream> int main() { const int i = 2; switch (i) { case 1: std::cout << '1'; case 2: // 执行从此 case 标签开始 std::cout << '2'; case 3: std::cout << '3'; [[fallthrough]]; // C++17 属性,用于消除贯穿警告 case 5: std::cout << "45"; break; // 终止后续语句的执行 case 6: std::cout << '6'; } std::cout << '\n'; switch (i) { case 4: std::cout << 'a'; default: std::cout << 'd'; // 没有匹配的常量表达式 // 因此执行 default 分支 } std::cout << '\n'; switch (i) { case 4: std::cout << 'a'; // 未执行任何语句 } // 当在 switch 语句中使用枚举时,如果某个枚举项未被处理 // 许多编译器会发出警告 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; } // 当不存在隐式转换到整型或枚举类型时 // C++17 的初始化语句语法会很有帮助 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; } // 特殊示例 // 语句不必是复合语句 switch (0) std::cout << "this does nothing\n"; // 标签也不需要复合语句 switch (int n = 1) case 0: case 1: std::cout << n << '\n'; }
输出:
2345 d red 1
缺陷报告
下列行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 适用标准 | 发布时行为 | 正确行为 |
|---|---|---|---|
| CWG 1767 | C++98 | 不适用于整型提升的类型所对应的 condition 无法被提升 |
不对这些类型的
condition 进行提升 |
| CWG 2629 | C++98 | condition 可以是浮点变量的声明 | 已禁止 |
参见
|
C 文档
关于
switch
|
外部链接
| 1. | 使用达夫设备实现循环展开 |
| 2. | 达夫设备可用于在C/C++中实现协程 |