C++17 一些新特性的简单描述
其实很多17的官方新特性早就被很多非官方的库支持,反复验证完善后被官方收录。
1、std::optional
std::optional<vector<int>> list = {} / std::nullopt / {{}};
不就是表示一个值存在与否是可选的吗
注意下{{}}和nullopt的区别,笔者偶尔遇见过相关bug,毕竟通信行业,信息内容中空列表和列表不存在还是不一样的0.0
使用的时候注意先用has_value判断,当然也可以像下面代码一样直接判断,用的时候.value()或者*解引用 来取值。
#include <iostream> #include <optional> #include <typeinfo> #include <vector> int main() { std::optional<std::vector<int>> list = {}; std::optional<std::vector<int>> list2 = std::nullopt; std::optional<std::vector<int>> list3 = {{}}; if (list) { std::cout << "list{} has value: " << typeid(list).name() << std::endl; } else { std::cout << "list{} does not have value" << std::endl; } if (list3) { std::cout << "list3{{}} has value," << " list3`s type: " << typeid(list3).name() << " (*list3)'s type: " << typeid(*list3).name() << " (list3.value())'s type: " << typeid(list3.value()).name() << std::endl; } else { std::cout << "list3{{}} does not have value" << std::endl; } if (list == list2) { std::cout << "{} equal std::nullopt" << std::endl; } else { std::cout << "{} not equal std::nullopt" << std::endl; } if (list3 == list2) { std::cout << "{{}} equal std::nullopt" << std::endl; } else { std::cout << "{{}} not equal std::nullopt" << std::endl; } return 0; }
2、结构化绑定
结构化绑定(Structured Bindings)是 C++17 中引入的一项特性,它允许将元组或其他复合类型的成员绑定到单独的变量中。这样做可以简化对复合类型数据的访问和处理,并提高代码的可读性和可维护性。
通过使用 auto
关键字和[] 将需要绑定的元组或复合类型的成员列表括起来。然后,编译器会根据变量的类型自动将相应的成员绑定到声明的变量中。
#include <iostream> #include <tuple> int main() { // 使用结构化绑定访问元组成员 std::tuple<int, std::string, double> myTuple{42, "Hello", 3.14}; auto [x, y, z] = myTuple; std::cout << "x: " << x << ", y: " << y << ", z: " << z << std::endl; // 使用结构化绑定访问数组元素 int arr[] = {1, 2, 3, 4, 5}; auto [a, b, c, d, e] = arr; std::cout << "a: " << a << ", b: " << b << ", c: " << c << ", d: " << d << ", e: " << e << std::endl; // 使用结构化绑定遍历容器 std::vector<int> vec{1, 2, 3, 4, 5}; for (auto [index, value] : enumerate(vec)) { std::cout << "Index: " << index << ", Value: " << value << std::endl; } return 0;
与for循环结合
#include <iostream> #include <vector> #include <utility> int main() { // 定义一个成员是 pair 的 vector std::vector<std::pair<int, double>> vec{{1, 3.14}, {2, 6.28}, {3, 9.42}}; // 使用结构化绑定访问 pair 的第二个元素 for (const auto& [-, value] : vec) { std::cout << "Second element of pair: " << value << std::endl; } return 0; }
3、if, switch语句中的初始化器
C++17引入了在if语句中使用初始化器的特性。这意味着可以在if语句的条件中初始化变量,并且作用域仅限于if语句的块中。这样做的主要目的是减少变量的作用域范围,从而增加代码的可读性和可维护性。
if:
#include <iostream> int main() { if (int x = 42; x > 0) { std::cout << "x is positive" << std::endl; } else { std::cout << "x is non-positive" << std::endl; } // 编译时错误:x不在这个作用域内可见 // std::cout << "x is: " << x << std::endl; return 0; }
switch与if类似:
#include <iostream> int main() { int option = 2; switch (int result = option * 2; result) { case 1: std::cout << "Result is 1" << std::endl; break; default: std::cout << "Result is not 1" << std::endl; break; } // 编译时错误:result 不在此作用域内可见 // std::cout << "Result is: " << result << std::endl; return 0; }
4、内联变量
C++17 增强了内联变量(inline variables)特性,允许在头文件中定义全局或静态变量而不会导致多重定义错误。内联变量的声明和定义都需要使用 inline
关键字。
静态常量表达式会被编译器默认添加inline。
// header.h #pragma once // 1、内联变量在头文件中定义,也就默认所有编译单元中这个变量定义是相同的 inline int globalVariable = 42; // 2、静态常量表达式变量会被编译器默认添加 inline 修饰 class MyClass { public: // 与 inline static constexpr int MAX_SIZE = 100;等效 static constexpr int MAX_SIZE = 100; };
5、折叠表达式
C++17 引入了折叠表达式(Fold Expressions)这一新特性,它允许以更简洁的方式处理模板参数包的展开。折叠表达式提供了一种在编译时展开参数包,并执行一系列操作的方法。
语法形式:(... op pack)
或 (pack op ...)
,其中 op
是一个二元操作符,pack
是模板参数包。通过使用不同的操作符和不同的展开方式,可以执行不同的操作,例如求和、求积、连接字符串等。
#include <iostream> #include <vector> #include <string> // 求和 template<typename... Args> auto sum(Args... args) { return (args + ...); } // 求积 template<typename... Args> auto product(Args... args) { return (args * ...); } // 连接字符串 template<typename... Args> std::string concatenate(Args... args) { return (args + ...); } // 打印参数包中的元素 template<typename... Args> void print(Args... args) { std::cout << ... << args << std::endl; } // 递归展开参数包并打印 template<typename T, typename... Args> void recursive_print(T t, Args... args) { std::cout << t << std::endl; if constexpr (sizeof...(args) > 0) { recursive_print(args...); } } int main() { // 使用折叠表达式求和、求积、连接字符串 std::cout << "Sum: " << sum(1, 2, 3, 4, 5) << std::endl; // Sum: 15 std::cout << "Product: " << product(1, 2, 3, 4, 5) << std::endl; // Product: 120 std::cout << "Concatenation: " << concatenate("Hello", ", ", "world", "!") << std::endl; // Concatenation: Hello, world! // 使用折叠表达式打印参数包中的元素 print("Hello", ", ", "world", "!"); // Hello, world! // 使用递归展开参数包并打印 recursive_print("Recursive", "print", "example"); // Recursive, print, example return 0; }
6、constexpr if
C++17 引入,它允许在编译时进行条件判断,并根据条件选择不同的代码路径执行。这种语法形式允许在模板和常量表达式中使用条件分支,以便根据编译时的条件来生成不同的代码。
if constexpr (condition) { // 如果 condition 为真,在编译时执行此代码块 // 只有在编译时符合条件才会生成这段代码 } else { // 如果 condition 为假,在编译时执行此代码块 // 只有在编译时不符合条件才会生成这段代码 }
由于 constexpr if
在编译时进行条件判断,所以不满足条件的代码路径在生成的代码中将被消除,这有助于优化生成的可执行代码。也就是说,未进入分支的语法错误是不被关注的哦。
简单的说明,有时间再深究
部分代码借助AI生成,懒,就是好评0.0
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端