C++17 if 与 switch 初始化语句
学习目标
完成本节学习后,应能够:
- 理解 C++17 中选择语句初始化器的作用;
- 掌握
if初始化语句的基本语法; - 掌握
switch初始化语句的基本语法; - 理解初始化变量的作用域;
- 在查找、加锁、解析返回值等场景中正确使用该语法;
- 避免常见的作用域和语法错误。
什么是选择语句初始化器
在 C++17 之前,程序员通常需要先定义变量,再在 if 或 switch 中使用它。
例如:
auto it = mp.find("apple");
if (it != mp.end()) {
std::cout << it->second << '\n';
}
这里的变量 it 在整个外层作用域中都存在,即使它只在判断语句中使用。
C++17 允许在 if 和 switch 的条件前直接写一条初始化语句:
if (auto it = mp.find("apple"); it != mp.end()) {
std::cout << it->second << '\n';
}
if 初始化语句
基本语法
C++17 中 if 初始化语句的基本形式如下:
if (初始化语句; 条件表达式) {
// 条件成立时执行
}
带 else 的形式:
if (初始化语句; 条件表达式) {
// 条件成立
} else {
// 条件不成立
}
其中,初始化语句和条件表达式之间使用分号分隔。
最简单的示例
#include <iostream>
using namespace std;
int getValue() {
return 10;
}
int main() {
if (int x = getValue(); x > 0) {
cout << "x 是正数,x = " << x << '\n';
}
return 0;
}
在这个例子中:
- 先执行
int x = getValue(); - 再判断
x > 0; - 如果条件成立,则进入
if语句块。
结合结构化绑定使用
C++17 中,初始化语句还可以和结构化绑定一起使用。
例如,map::insert 会返回一个 pair:
- 第一个元素是迭代器;
- 第二个元素表示是否插入成功。
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> scores;
if (auto [it, inserted] =
scores.insert({"Alice", 95});
inserted) {
cout << "插入成功" << '\n';
} else {
cout << "键已经存在" << '\n';
}
return 0;
}
在条件表达式中直接判断 inserted。
如果插入失败,仍可在 else 分支通过 it 访问已经存在的元素:
if (auto [it, inserted] =
scores.insert({"Alice", 95});
inserted) {
cout << "插入成功" << '\n';
} else {
cout << "已有分数:" << it->second << '\n';
}
处理函数返回值
如果一个函数返回状态码,可以在 if 中完成调用、保存结果和判断。
#include <iostream>
using namespace std;
int connectServer() {
return 0;
}
int main() {
if (int code = connectServer(); code == 0) {
cout << "连接成功" << '\n';
} else {
cout << "连接失败,错误码:" << code << '\n';
}
return 0;
}
这里的 code 只用于当前判断,因此不需要放到外层作用域。
switch 初始化语句
基本语法
C++17 允许在 switch 中加入初始化语句:
switch (初始化语句; 条件表达式) {
case 常量1:
// ...
break;
case 常量2:
// ...
break;
default:
// ...
break;
}
简单示例
#include <iostream>
using namespace std;
int getCommand() {
return 2;
}
int main() {
switch (int command = getCommand(); command) {
case 1:
cout << "添加" << '\n';
break;
case 2:
cout << "删除" << '\n';
break;
case 3:
cout << "查询" << '\n';
break;
default:
cout << "未知命令" << '\n';
break;
}
return 0;
}
这里先定义变量 command,然后以 command 的值进行分支选择。
switch 初始化变量的作用域
初始化变量的作用域覆盖:
switch条件表达式;- 所有
case分支; default分支。
离开整个 switch 后,变量失效。
switch (int code = getCommand(); code) {
case 1:
cout << code << '\n';
break;
default:
cout << code << '\n';
break;
}
// cout << code; // 错误:code 已离开作用域
switch 的实际应用
假设一个函数返回命令类型:
enum class Command {
Add,
Remove,
Search,
Unknown
};
Command readCommand() {
return Command::Search;
}
可以使用:
switch (auto cmd = readCommand(); cmd) {
case Command::Add:
cout << "执行添加操作" << '\n';
break;
case Command::Remove:
cout << "执行删除操作" << '\n';
break;
case Command::Search:
cout << "执行查询操作" << '\n';
break;
default:
cout << "未知操作" << '\n';
break;
}
这种写法把命令获取和命令分支处理放在同一个结构中。
if 与 switch 初始化语句对比
| 项目 | if 初始化语句 | switch 初始化语句 |
| 引入版本 | C++17 | C++17 |
| 分隔符 | 分号 | 分号 |
| 适用判断 | 任意布尔条件 | 整数、枚举等离散值 |
| 变量作用域 | 整个 if--else | 整个 switch |
| 常见用途 | 查找、插入、指针判断 | 命令码、状态码、枚举 |
常见错误
忘记写分号
错误:
if (int x = getValue() x > 0) {
}
正确:
if (int x = getValue(); x > 0) {
}
在语句外使用变量
if (int x = 10; x > 0) {
cout << x << '\n';
}
cout << x << '\n'; // 错误
变量 x 的作用域只到 if 语句结束。
误以为只能定义变量
初始化语句不一定必须是变量声明,也可以是普通表达式语句。
例如:
int x = 0;
if (x = getValue(); x > 0) {
cout << x << '\n';
}
不过教学和实际开发中,更常见的是在初始化语句中声明局部变量。
在多个变量声明中使用不同类型
下面的写法错误:
if (int x = 1, double y = 2.0; x < y) {
}
同一条声明语句中不能这样混合声明不同类型。
可以改为使用结构体、pair 或 tuple,或者提前声明其中一个变量。
综合示例:用户查询系统
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
map<string, int> users{
{"Alice", 1001},
{"Bob", 1002},
{"Tom", 1003}
};
string name;
cin >> name;
if (auto it = users.find(name);
it != users.end()) {
cout << "用户编号:" << it->second << '\n';
} else {
cout << "用户不存在" << '\n';
}
return 0;
}
这个程序中,迭代器 it 只用于查询结果判断,因此放在 if 初始化语句中最合适。
知识总结
板书式速记
// if 初始化语句
if (auto value = getValue(); value > 0) {
// ...
} else {
// ...
}
// 容器查找
if (auto it = mp.find(key); it != mp.end()) {
// ...
}
// 结构化绑定
if (auto [it, inserted] = s.insert(x); inserted) {
// ...
}
// switch 初始化语句
switch (auto cmd = getCommand(); cmd) {
case 1:
break;
default:
break;
}