C++17新特性总结

C++17 是继 C++14 之后的一个重要版本,引入了许多新特性和改进,旨在提高编程效率、简化代码以及增强标准库的功能。以下是 C++17 中的一些关键新特性:

1. Lambda 表达式捕获 *this:
在 C++17 之前,lambda 表达式只能通过引用捕获 this。C++17 允许直接捕获 *this 作为值,使得在 lambda 中可以拥有当前对象的副本,即使原对象在其生命周期之外被销毁也不会影响 lambda 的行为。

2. 自动类型推导的增强:
对 auto 关键字的类型推导规则进行了扩展和改进,特别是在模板参数推导和返回类型推导方面。例如,引入了 auto 作为函数返回类型的模板推导(auto 函数),编译器能够根据函数体中的返回语句自动推断返回类型。

3. 内联变量:
允许在头文件中声明并定义(用 inline 关键字修饰)全局或命名空间作用域的变量,而不用为该变量特地创建一个cpp文件,解决了在多个编译单元中重复定义相同全局变量导致的“重复定义”的链接问题,同时保持了内联函数的优点,如提高代码复用和潜在的性能提升。

4. 条件(if)初始化语句:
在 if 和 switch 语句中可以直接初始化一个变量作为条件表达式的一部分,无需预先声明和赋值。这种写法更加简洁,减少了临时变量的使用。

if (int* p = createPtr(); !p) {
	// using 'p' to do something;
	delete p;
}

5. 结构化绑定:
可以一次性解构并绑定复合数据类型(如元组、数组、结构体等)的多个成员到不同的局部变量,简化了多值返回或复杂数据结构的访问。

std::map<std::string, int> my_map;
std::tuple<int, std::string, const char*> my_tuple;
for (const auto& [key, value] : my_map) {
	// do something
}
auto [m1, m2, m3] = my_tuple;

6. 折叠表达式:
提供了一种简洁的方式来编写递归模板元编程表达式,特别是在处理参数包时,能够对参数包中的元素进行统一的操作(如求和、逻辑与/或等),详见:折叠表达式的使用

7. std::variant:
引入了一个新的标准库类型 std::variant,它是一个安全的、可选类型的容器,可以在其中存储一组预定义类型的任何一个。类似于联合体(union),但提供了类型安全的访问和操作机制。

#include <variant>

std::variant<int, const char*, std::string, double> value;
value = 1;
std::get<int>(value);

value = 2.1;
std::get<double>(value);

value = "hello";
std::get<const char*>(value);

value = std::string("hello");
std::get<std::string>(value);

更多关于variant的使用请参考此处

8. std::optional:
添加了 std::optional 类型,用于表示可能有值也可能没有值(空)的状态,避免了使用 NULL 指针或者特定值(如 0、-1)来表示“无值”的情况,增强了类型系统的表达力和安全性。

#include <optional>

std::optional<std::string> getStr(int cond) {
	if (cond < 0) {
		return std::nullopt;
	}
	std::string str;
	// do something for str
	return str;
}

auto str_opt = getStr(1);
if (str_opt) {
	std::cout << *str_opt << std::endl;
}

9. std::any
引入了 std::any 类型,可以存储任意类型的数据,提供了类型擦除的动态存储能力,用于需要存储未知类型数据的场景,如事件系统或跨模块通信。

#include <any>

std::any value1 = 1;
int v = std::any_cast<int>(value1);

std::any value2 = "xyz";
const char* str = std::any_cast<const char*>(value2);

std::any value3 = std::vector<int>{1, 2, 3};
auto b = std::any_cast<std::vector<int>>(value3);

10. std::string_view:
它提供了一种安全且高效的方式来引用或查看已存在的字符串数据,而无需复制该数据或管理其内存。函数在处理只读字符串时,往往支持两种类型const std::string&和std::string,此时使用string_view有明显的优势:

  • 兼容两种字符串类型,减少类型转换和内存分配。如果传入的是明文字符串const char*, const std::string&需要进行一次内存分配,将字符串拷贝到堆上,而std::string_view则可以避免。
  • 在处理子串时,std::string::substr也需要进行拷贝和内存分配,而std::string_view::substr则不需要,在处理大文件解析时,性能优势非常明显。
#include <string_view>

void func(std::string_view str) {
	// do something
}

string_view并不拷贝内存,所以要特别注意它所指向的字符串的生命周期。string_view指向的字符串,不能再string_view死亡之前被回收。

11. 文件系统库:
标准库中新增了文件系统库std::filesystem,提供了一系列操作文件和目录的跨平台接口,包括路径操作、目录遍历、文件属性查询等。

12. 改进的模板元编程工具:
包括 constexpr if(条件编译指令),允许在编译时根据常量表达式的值选择执行不同的代码块;以及对模板参数推导规则的改进,如类模板参数推导。

  • 29
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值