C++17 新特性

概述

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 只在函数内部短生命周期使用。

滚动至顶部