C++17--继 C++11 之后又一次实质性增强的 C++ 标准

C++17--继 C++11 之后又一次实质性增强的 C++ 标准

C++17(ISO/IEC 14882:2017)是继 C++11 之后又一次实质性增强的 C++ 标准,虽未引入像“概念(Concepts)”这类革命性特性(后者推迟至 C++20),但通过大量语言简化、库扩展和现代化改进,显著提升了开发效率、代码安全性和表达能力。

以下是对 C++17 新特性的全面、系统化总结,涵盖语言核心、标准库、实用示例及最佳实践。


一、设计目标

  • 简化语法(减少样板代码)
  • 提升类型安全
  • 增强泛型与模板编程
  • 完善并行与文件系统支持
  • 为 C++20 铺路
✅ C++17 被广泛认为是“最实用的现代 C++ 版本之一”,适合大规模生产环境采用。

二、语言核心新特性

1. 结构化绑定(Structured Bindings)

从数组、元组、结构体等一次性解包多个值

// 从 std::pair / std::tuple

auto [name, age] = std::make_pair("Alice", 30);

auto [x, y, z] = std::make_tuple(1, 2.5, "hello");

// 从结构体(需 public 成员)

struct Point { double x, y; };

Point p{1.0, 2.0};

auto [a, b] = p;

// 从 map 迭代

std::map<std::string, int> m{{"a", 1}, {"b", 2}};

for (const auto& [key, value] : m) {

    std::cout << key << ": " << value << "\n";

}

⚠️ 绑定的是副本或引用,可通过 auto& 或 const auto& 控制:

for (auto& [k, v] : m) v *= 2; // 修改 map 中的值

2. 类模板参数推导(Class Template Argument Deduction, CTAD)

编译器根据构造函数参数自动推导模板参数

// C++14 需显式指定类型

std::pair<int, std::string> p1(42, "hello");

std::vector<int> v1{1, 2, 3};

// C++17:自动推导

std::pair p2(42, "hello");        // pair<int, const char*>

std::vector v2{1, 2, 3};          // vector<int>

// 自定义类也支持(通过 deduction guide)

template<typename T>

struct MyContainer {

    MyContainer(T t) : value(t) {}

    T value;

};

// 若无 deduction guide,以下会失败

MyContainer c(42); // ❌ C++17 默认不推导用户类

// 添加 deduction guide(通常放在类定义后)

template<typename T>

MyContainer(T) -> MyContainer<T>;

MyContainer c2(42); // ✅ 推导为 MyContainer<int>

✅ 极大简化 STL 容器和智能指针使用:

std::scoped_lock lock(mtx1, mtx2); // 无需指定 Mutex 类型

3. if 和 switch 的初始化语句(Init-statement)

在条件语句中局部声明变量,限制作用域:

// 文件打开 + 检查

if (std::ifstream file{"config.txt"}; file.good()) {

    // file 在此作用域内有效

    parse(file);

} // file 自动析构

// 锁 + 条件检查

if (auto lock = std::unique_lock(mtx); !queue.empty()) {

    process(queue.front());

}

✅ 避免变量泄漏到外层作用域,提升 RAII 安全性。

4. 内联变量(Inline Variables)

解决头文件中定义全局变量的 ODR(One Definition Rule)问题

// math_constants.h

inline constexpr double pi = 3.141592653589793;

inline std::string project_name = "MyApp"; // 非 constexpr 也可 inline

// 多个 .cpp 包含此头文件不会链接错误

✅ 替代传统的 extern const + 单独定义模式

5. 折叠表达式(Fold Expressions) — 模板元编程利器

对参数包(parameter pack)进行一元或二元操作折叠

// 变参模板求和

template<typename... Args>

auto sum(Args... args) {

    return (args + ...); // (arg1 + (arg2 + (arg3 + ...)))

}

sum(1, 2, 3, 4); // 10

// 布尔逻辑

template<typename... Args>

bool all_true(Args... args) {

    return (args && ...); // arg1 && arg2 && ...

}

// 带初始值

template<typename... Args>

auto product(Args... args) {

    return (args * ... * 1); // 右折叠:args * ... * 1

}

支持:+*&&||, 等二元操作符。

6. constexpr Lambda

Lambda 表达式可标记为 constexpr,用于编译期计算:

constexpr auto square = [](int x) { return x * x; };

constexpr int val = square(5); // 编译期计算

// 甚至可在常量表达式中使用

std::array<int, square(4)> arr; // size = 16

✅ 结合泛型 Lambda,实现强大的编译期函数对象。


7. [[nodiscard]] 属性

提示返回值不应被忽略,否则编译器警告:

[[nodiscard]] error_code do_something() {

    return success;

}

void test() {

    do_something(); // 警告:返回值被忽略!

}

标准库广泛使用(如 std::asyncstd::lock_guard 构造函数)。

8. static_assert 允许无消息

static_assert(sizeof(int) == 4); // C++17 OK

// C++11 必须:static_assert(sizeof(int) == 4, "int must be 4 bytes");

三、标准库重大增强

1. 文件系统库(<filesystem> — 重磅功能!

提供跨平台文件/目录操作(基于 Boost.Filesystem):

#include <filesystem>

namespace fs = std::filesystem;

// 遍历目录

for (const auto& entry : fs::directory_iterator("/tmp")) {

    if (entry.is_regular_file()) {

        std::cout << entry.path() << " (" << entry.file_size() << "B)\n";

    }

}

// 创建目录

fs::create_directories("output/logs");

// 路径操作

fs::path p = "/home/user/data.txt";

std::cout << p.stem() << "\n";     // "data"

std::cout << p.extension() << "\n"; // ".txt"

✅ 终于告别 system("mkdir") 或平台相关 API!

2. 并行算法(Parallel Algorithms)

STL 算法支持并行执行策略(需编译器支持,如 GCC 9+、MSVC):

#include <execution>

#include <algorithm>

std::vector<int> v(1000000);

// 并行排序

std::sort(std::execution::par, v.begin(), v.end());

// 并行 for_each

std::for_each(std::execution::par_unseq, v.begin(), v.end(), [](int& x) {

    x *= 2;

});

执行策略:

  • seq:顺序(默认)
  • par:并行(多线程)
  • par_unseq:并行 + 向量化(SIMD)
⚠️ 需确保操作无数据竞争可重排

3. std::optional — 安全表示“可能无值”

替代“魔数”(如 -1、nullptr)或输出参数:

std::optional<int> find_value(const std::string& key) {

    if (map.contains(key))

        return map[key];

    return std::nullopt; // 或直接 return {};

}

auto result = find_value("age");

if (result) {

    std::cout << "Age: " << *result << "\n";

} else {

    std::cout << "Not found\n";

}

✅ 比裸指针更安全,比异常更轻量。

4. std::variant — 类型安全的联合体(Union)

替代 union 或 void*,支持有限类型集合:

#include <variant>

using Value = std::variant<int, double, std::string>;

Value v1 = 42;

Value v2 = 3.14;

Value v3 = "hello";

// 访问:使用 std::visit

std::visit([](const auto& val) {

    std::cout << val << "\n";

}, v1);

// 获取特定类型

if (std::holds_alternative<int>(v1)) {

    int x = std::get<int>(v1);

}

✅ 无未定义行为,支持访问者模式。

5. std::any — 任意类型的容器

类似 void*,但类型安全

std::any a = 42;

a = 3.14;

a = std::string("hello");

if (a.type() == typeid(std::string)) {

    std::string s = std::any_cast<std::string>(a);

}

适用于插件系统、配置解析等需要动态类型的场景。

6. std::string_view — 零拷贝字符串视图

避免不必要的字符串复制(尤其函数传参):

void process(std::string_view sv) {

    // sv 可接受 const char*, std::string, 字面量等

    std::cout << sv.substr(0, 5) << "\n";

}

process("hello world");           // 无拷贝

process(my_string);               // 无拷贝(仅传递指针+长度)

⚠️ 不拥有数据!确保底层字符串生命周期长于 string_view

7. std::shared_mutex(简化版)

C++14 有 std::shared_timed_mutex,C++17 提供更轻量的 std::shared_mutex(无超时支持):

std::shared_mutex mtx;

// 读锁

std::shared_lock lock(mtx);

// 写锁

std::unique_lock lock(mtx);

8. 其他实用工具

工具

说明

std::byte

表示原始字节(非字符/整数),用于内存操作

std::invoke

统一调用函数对象、成员函数、成员变量

std::apply

将 tuple 解包为函数参数:
std::apply(f, std::make_tuple(1, 2));

std::clamp

限制值在 [min, max] 范围内

std::gcd

 / std::lcm

最大公约数 / 最小公倍数

// clamp 示例

int score = std::clamp(user_input, 0, 100); // 保证 0 ≤ score ≤ 100

四、弃用与移除(C++17)

特性

状态

动态异常规范(throw(...)

移除

std::auto_ptr

移除

register

 关键字

弃用(保留但无作用)

std::random_shuffle

弃用(用 std::shuffle 替代)


五、C++17 vs C++14 对比速查

特性

C++14

C++17

结构化绑定

CTAD(类模板推导)

if

/switch 初始化

<filesystem>

并行 STL

std::optional

std::variant

std::any

std::string_view

折叠表达式

内联变量


六、最佳实践建议

  1. 优先使用 string_view 代替 const std::string& 作为函数参数
  2. 用 optional 表示可能失败的返回值
  3. 用 variant/any 替代 union 或 void*
  4. 利用结构化绑定简化 tuple/map 解包
  5. 在条件语句中使用初始化语句管理 RAII 对象
  6. 启用并行算法加速大数据处理(注意线程安全)
  7. 使用 filesystem 进行跨平台文件操作

七、总结

C++17 是“现代化 C++”的成熟体现
它没有追求激进创新,而是聚焦于开发者日常痛点——简化语法、增强安全、补齐基础设施(如文件系统),使得 C++ 在系统编程、高性能计算、嵌入式等领域继续保持强大竞争力。

如今,主流编译器(GCC ≥8, Clang ≥5, MSVC ≥2017)已完整支持 C++17,强烈推荐新项目采用。

欢迎扫描关注,持续交流学习!! 

代码之外的风景:程序员如何平衡工作与生活的艺术

山海重光:当〈山海经〉的神兽踏进芯片,古老幻想在硅基世界涅槃重生

SQLite不止于轻量:揭秘万亿级部署背后的核心力量​

汇聚技术达人,深耕技术探讨,共享资源干货,解锁行业新知,技术交流微信群诚邀您加入!

Read more

《算法闯关指南:动态规划算法--斐波拉契数列模型》--01.第N个泰波拉契数,02.三步问题

《算法闯关指南:动态规划算法--斐波拉契数列模型》--01.第N个泰波拉契数,02.三步问题

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 01.第N个泰波拉契数 * 解法(动态规划): * 算法流程: * C++算法代码: * 算法总结&&笔记展示: * 02.三步问题 * 解法(动态规划): * 算法思路: * C++算法代码: * 算法总结&&笔记展示: * 结尾: 前言: 聚焦算法题实战,系统讲解三大核心板块:优选算法:剖析动态规划、二分法等高效策略,学会寻找“最优解”。 递归与回溯:掌握问题分解与状态回退,攻克组合、排列等难题。 贪心算法:理解“

By Ne0inhk
数据结构-单链表

数据结构-单链表

单链表 * 概念与结构 * 结点 * 链表的性质 * 链表的打印 * 实现单链表 * 头文件 * 源文件 * 单链表的打印 * 单链表申请新节点内存 * 尾插 * 头插 * 尾删 * 头删 * 查找 * 在指定位置之前插入数据 * 在指定位置之后插入数据 * 删除pos结点 * 删除pos之后的结点 * 销毁链表 * 链表的分类 * 代码地址 概念与结构 概念:链表是⼀种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 逻辑结构:线性 物理结构(存储结构):不一定是线性的 链表就类似一个火车,车头是哨兵位(可有可无),车厢是节点 * 将火车里的某节车厢去掉或加上,不会影响其他车厢,每节车厢都是独立存在的。 在链表⾥,每节“车厢”是什么样的呢? \color{red}{在链表⾥,每节“车厢”是什么样的呢?

By Ne0inhk
Flutter 三方库 matrix 鸿蒙终端底层复杂超维数学算力适配突破:无缝植入极限级张量系统与密集线性代数矩阵运算推演算法,解锁端侧图形处理边界-适配鸿蒙 HarmonyOS ohos

Flutter 三方库 matrix 鸿蒙终端底层复杂超维数学算力适配突破:无缝植入极限级张量系统与密集线性代数矩阵运算推演算法,解锁端侧图形处理边界-适配鸿蒙 HarmonyOS ohos

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 matrix 鸿蒙终端底层复杂超维数学算力适配突破:无缝植入极限级张量系统与密集线性代数矩阵运算推演算法,全面解锁端侧图形视觉处理边界并拔高数据分析算力上限 在图形学渲染、物理引擎模拟、复杂地理坐标转换以及端侧小型机器学习框架中,底层的矩阵运算(Matrix Operations)是决速步骤。matrix 库是一个专注于高性能线性代数计算的 Dart 库。本文将详解该库在 OpenHarmony 环境下的适配与实战应用。 封面 前言 什么是 matrix?它为 Dart 提供了一套类似于 NumPy 的多维数组运算接口。在鸿蒙操作系统这种强调极致流畅度和复杂视觉动效的系统中,利用高效的矩阵算法可以显著提升自定义 Canvas 绘图或实时传器数据处理的性能,避免因 Dart 层的低效循环导致的 UI 掉帧。 一、原理解析 1.1 基础概念 matrix 库核心基于

By Ne0inhk
LeetCode 141题:环形链表的艺术与科学

LeetCode 141题:环形链表的艺术与科学

🌟 LeetCode 141题:环形链表的艺术与科学 * 🌀 环形链表:当数据开始循环舞蹈 * 🔍 解法一:哈希表法 - 记忆的艺术 * 解题思路 * 性能分析 * 🏃‍♂️ 解法二:快慢指针法 - 龟兔赛跑的智慧 * 解题思路 * 性能优势 * 💻 代码实现与调试心得 * 🌈 思维与实现的分离 * 🎯 总结 因为想更好地为义父义母大佬服务,本文 Bilibili 视频地址 🌀 环形链表:当数据开始循环舞蹈 在计算机科学的世界里,链表是一种优雅而基础的数据结构。正常链表如同一条笔直的小路,从起点(head)出发,每个节点指向下一个节点,最终以空指针(nullptr)作为终点,标志着旅程的结束。 Head Node1 Node2 Node3 nullptr 然而,环形链表则打破了这种线性规则,它更像是一个神秘的莫比乌斯环,没有真正的终点。链表的某个节点不再指向空,而是指向链表中已经存在的另一个节点,形成了一个无尽的循环。 Head

By Ne0inhk