概述
C++17(ISO/IEC 14882:2017,2017 年 12 月发布)被称为”给开发者用的版本”——它没有像 C++11 那样引入革命性概念,但提供了大量让日常代码更简洁的语法糖和实用库。以下按主题整理核心特性。
一、结构化绑定
// 元组解包
auto [x, y, z] = std::make_tuple(1, 2.5, "hello");
// map 遍历(省去 first/second)
std::map<int, std::string> m = {{1, "one"}, {2, "two"}};
for (const auto& [key, val] : m) {
std::cout << key << ": " << val << 'n';
}
// 结构体成员绑定
struct Point { int x; int y; };
Point p{10, 20};
auto [px, py] = p;
二、if/switch 初始化语句
if (auto it = m.find(1); it != m.end()) {
std::cout << it->second << 'n'; // it 只在 if 作用域内可见
}
switch (int n = rand() % 3; n) {
case 0: /*...*/ break;
default: break;
}
三、内联变量
// 头文件中定义,避免 ODR 多重定义错误
inline int global_counter = 0;
class MyClass {
inline static int count = 0; // 类内直接初始化静态成员
};
四、折叠表达式
template<typename... Args>
auto sum(Args... args) { return (... + args); } // 一元右折叠
template<typename... Args>
void print(Args... args) {
(std::cout << ... << args) << 'n'; // 二元左折叠
}
print("Hello", " ", "World");
五、optional / variant / any
// optional:可能没有值
std::optional<int> find(int key) {
if (key > 0) return key * 2;
return std::nullopt;
}
if (auto v = find(5)) { /* v 有值 */ }
int r = find(-1).value_or(0); // 默认值
// variant:类型安全的联合体
std::variant<int, double, std::string> v = 42;
std::visit([](auto&& arg) { std::cout << arg << 'n'; }, v);
// any:任意类型(运行时类型安全)
std::any a = 42;
a = std::string("hello");
auto s = std::any_cast<std::string>(a); // 类型不对抛 bad_any_cast
六、文件系统库
#include <filesystem>
namespace fs = std::filesystem;
for (auto& p : fs::directory_iterator(".")) {
std::cout << p.path() << 'n';
}
if (fs::exists("test.txt")) {
auto sz = fs::file_size("test.txt");
fs::rename("test.txt", "new.txt");
}
七、并行算法
#include <execution>
std::vector<int> v(1000000);
std::sort(std::execution::par, v.begin(), v.end()); // 并行排序
auto it = std::find_if(std::execution::par, v.begin(), v.end(),
[](int x) { return x > 100; });
八、if constexpr(编译期 if)

template<typename T>
auto get_value(T t) {
if constexpr (std::is_pointer_v<T>) return *t; // 只有指针分支参与实例化
else return t;
}
九、类模板参数推导(CTAD)
std::pair p(1, 2.5); // 自动推导 pair<int, double>
std::vector v{1, 2, 3}; // 自动推导 vector<int>
// 自定义推导指南
template<typename T> struct MyContainer { MyContainer(T t); T value; };
MyContainer(const char*) -> MyContainer<std::string>;
十、string_view 与嵌套命名空间
// 零拷贝字符串视图(借用语义,注意生命周期)
void process(std::string_view sv) { /* 不拷贝 */ }
process("Hello World");
// 嵌套命名空间
namespace A::B::C { /* C++17 写法 */ }
十一、其他补充
// [[maybe_unused]]:抑制未使用警告
void foo(int x, [[maybe_unused]] int y) { std::cout << x << 'n'; }
// std::byte:类型安全的字节操作
std::byte b{0x7F}, mask{0xF0};
auto r = b & mask;
重要改进总结
| 类别 | 主要特性 |
|---|---|
| 语法增强 | 结构化绑定、if/switch 初始化、折叠表达式、if constexpr |
| 类型系统 | optional、variant、any、string_view |
| 库扩展 | 文件系统、并行算法、std::byte |
| 模板改进 | 类模板参数推导、auto 非类型模板参数 |
| 其他 | 内联变量、嵌套命名空间、属性增强 |
实战体会
结构化绑定是提升日常幸福感最高的特性。以前解包 map 遍历、pair 返回值都要写 first/second 或临时变量,现在 for (const auto& [key, val] : map) 一行解决,代码意图清楚得多。
optional 替代哨兵值,把语义写进类型里。以前”查不到就返回 -1″,调用方根本不知道 -1 是什么意思;换成 std::optional 后,函数签名本身就声明了”可能没有值”,配合 has_value() 检查,线上少了很多边界 bug。
string_view 是零拷贝利器,但要记住它是”借用”语义。解析协议、切字符串时用 string_view 几乎不分配内存;但它不拥有数据,持有它的生命周期不能超过底层字符串——和 C++ 惯有的值语义思维相反,团队里我要求 string_view 只在函数内部短生命周期使用。

