现代 C++ 实战(07):C++17 工具箱
C++17 不像 C++11 / C++20 那样「改天换地」,却塞进了大量日常极好用的工具:std::any、std::filesystem、结构化绑定、if constexpr、折叠表达式、并行算法……写业务代码时经常伸手就能摸到。
这一篇把 C++17 工具箱里最常用的一批串起来,对应三个 demo:any_demo、filesystem_demo、parallel_algo_demo。
这是「现代 C++ 实战」系列的第 7 篇。建议先读 第 06 篇:Lambda 与类型推导。
一、std::any:运行期存任意类型
C++17 的 std::any 是类型擦除容器——运行期可以换成 int、string、vector……类型信息保存在内部,取出时用 std::any_cast。
1 |
|
| 成员 / 操作 | 作用 |
|---|---|
has_value() |
是否为空 |
type() |
返回 type_info |
reset() |
清空 |
any_cast<T>(a) |
按类型取出(引用版抛异常,指针版返回 nullptr) |
与 void*、std::variant 怎么选?
void* |
std::variant<A,B,C> |
std::any |
|
|---|---|---|---|
| 类型信息 | 无 | 编译期固定集合 | 运行期任意 |
| 内存 | 手动管理 | 通常栈上、无堆 | 大对象可能堆分配 |
| 典型场景 | C 遗留接口 | 状态机、有限联合 | 配置表、插件返回值 |
选型:类型集合编译期已知 → variant(更快);运行期才知道类型 → any。
demo 里用 map<string, any> 实现简易配置系统——set("port", 8080)、get<int>("port"),见 ref/cpp_demo/basics/any_demo/。
二、std::filesystem:跨平台文件系统
C++17 把文件系统操作收进标准库,告别「Windows 用一套 API、Linux 用另一套」:
1 |
|
| 常用 API | 用途 |
|---|---|
fs::path |
路径拼接 a / b、取 stem() / extension() |
exists / file_size / last_write_time |
属性查询 |
directory_iterator |
单层目录遍历 |
recursive_directory_iterator |
递归遍历 |
create_directories / remove_all |
创建 / 删除 |
copy / copy_file / rename |
复制与重命名 |
path 自动处理 / 与 \,同一套代码在 macOS / Linux / Windows 上都能编译(链接时需 -lc++fs 的旧 GCC 除外)。
完整示例见 ref/cpp_demo/basics/filesystem_demo/。
三、结构化绑定:一次拆多个返回值
C++17 允许把 pair、tuple、数组、结构体成员一次性绑定到多个变量:
1 | std::map<std::string, int> m{{"a", 1}, {"b", 2}}; |
配合 range-for 遍历 map 特别顺手——不用再写 .first / .second。
四、if constexpr:编译期分支
模板里按类型走不同逻辑,C++17 之前要靠 SFINAE;if constexpr 让不走的分支不参与实例化:
1 | template<typename T> |
if constexpr 在编译期决定走哪条分支;普通 if 两条分支都必须能编译通过。
五、折叠表达式:可变参数一行求和
C++17 折叠表达式简化了可变参数模板:
1 | template<typename... Args> |
| 形式 | 示例 | 含义 |
|---|---|---|
| 一元右折叠 | (args + ...) |
arg1 + (arg2 + (...)) |
| 一元左折叠 | (... + args) |
((...) + arg2) + arg1 |
| 二元折叠 | (args + ... + 0) |
带初始值 |
六、并行算法:std::execution::par
C++17 为部分 STL 算法增加了执行策略参数:
1 |
|
| 策略 | 含义 |
|---|---|
std::execution::seq |
顺序(默认行为) |
std::execution::par |
允许多线程并行 |
std::execution::par_unseq |
并行 + 允许 SIMD 向量化 |
注意:
- 数据量小时并行反而更慢(线程开销)
par_unseq要求操作无锁、无分配——纯计算最合适- Apple Clang / libc++ 可能头文件存在但未真正实现并行策略;demo 用
__cpp_lib_parallel_algorithm宏检测,不支持时回退顺序执行
并行算法底层通常用标准库自带的线程池,不是你自己写的线程池(系列第 14 篇会讲自建线程池)。
性能对比见 ref/cpp_demo/basics/parallel_algo_demo/——对百万级 sort / reduce 用 chrono 计时。
七、三个 demo 怎么跑
1 | cd ref/cpp_demo/basics/any_demo && ./build.sh --run |
CMake 里记得 set(CMAKE_CXX_STANDARD 17);filesystem 在 GCC 8 以前可能需要链接 stdc++fs。
八、小结
| 特性 | 一句话 |
|---|---|
std::any |
运行期任意类型,配置 / 插件场景 |
std::filesystem |
跨平台路径与文件操作 |
| 结构化绑定 | auto [k,v] 解构 map / pair |
if constexpr |
模板内编译期分支 |
| 折叠表达式 | (args + ...) 简化可变参数 |
| 并行算法 | std::execution::par 加速大数组算法 |
现代 C++ 实战系列第 7 篇完。下一篇 错误处理策略——错误码、异常、optional、expected 各走哪条路。
系列导航
| 篇号 | 标题 | 状态 |
|---|---|---|
| 06 | Lambda 与类型推导 | ✅ |
| 07 | C++17 工具箱(本篇) | ✅ |
| 08 | 错误处理策略 | 下一篇 |
完整大纲见工作区 docs/CPP_SERIES_OUTLINE.md。










