c++17新特性
移除
auto_ptr
被移除
由于以下原因被移除
- 语义不清晰。
auto_ptr
的拷贝被改写为移动,很容易让认误解。在拷贝时原指针被赋NULL
,很容易导致重大错误。 - 风格与现代c++不符,移动操作现在已经有移动语义了。现在右值转发都使用移动语义进行,显得
auto_ptr
的这种拷贝移动更奇怪了。
功能上,原来使用auto_ptr
可以由unique_ptr
替代。
random_shuffle
被移除
random_shuffle
打乱两个迭代器之间的数据。功能被更强大的shuffle
替代,因此移除
unexpected
被移除
若函数抛出了未列于其异常说明的类型的异常,则调用函数 unexpected
。缺省的函数调用 terminate
,但它可以(通过 set_unexpected
)替换为用户提供的函数,可能调用 terminate
或抛出异常。若从 unexpected
抛出的异常为异常说明所接受,则栈回溯照常持续。若它不被接受,但异常说明允许 bad_exception
,则抛出 bad_exception
。否则,调用 terminate
。
这个和throw
语法是一个体系的,随着异常说明整个体系的大概,unexpected
也取消了。不知道为什么要改,也不知道没改之前怎么用的。现在高阶异常编程用的也少,等下次用到再说。
三标符被移除
这个是早期c++的奇怪特性,用来字符替换的。被用的极少,替换了就算了。
新增
折叠表达式
用来配合形参包语法的。看下面例子就懂了。
template<typename... Args>
bool all(Args... args) { return (... && args); }
bool b = all(true, true, true, false);
// 在 all() 中,一元左折叠展开成
// return ((true && true) && true) && false;
// b 为 false
void printer(Args&&... args) {
(std::cout << ... << args) << '\n';
}
// 此函数将参数一个个打出
类模板实参推导
原来c++有个泛型函数自动推导类型的,现在模板类也可以了。
std::pair p(2, 4.5); // 推导出 std::pair<int, double> p(2, 4.5);
std::tuple t(4, 3, 2.5); // 同 auto t = std::make_tuple(4, 3, 2.5);
std::less l; // 同 std::less<void> l;
auto 占位的非类型模板形参
泛型方法可以配置若干的模板形参,里面有类型的和非类型的。例如template<T,int a>
里面,就有这两种,非类型的一般用来完成函数式编程的有个什么xxx化(忘了,回头查查)。现在可以不写具体的类型,用auto
、auto&
以及其他系列的占位了。
当然由于历史原因,c++20前不支持浮点型作为非类型形参。
if优化
主要优化了两个地方。
- 条件可以加上constexpr,后接一个编译期的函数
template <typename T>
auto get_value(T t) {
if constexpr (std::is_pointer_v<T>)
return *t; // 对 T = int* 推导返回类型为 int
else
return t; // 对 T = int 推导返回类型为 int
}
- 条件前可以加一个初始化语句
if (auto it = m.find(10); it != m.end()) { return it->second.size(); }
inline
优化
inline
的定义从允许内联改为允许多次定义(编译时不会编译为不同地址)。因此inline
可以适用于变量。一般用于在多个文件中引用的头文件中定义某一个变量或(全局变量),或者在头文件中进行某种类初始化(此时将类中需要如此操作的变量定义为inline)
结构化绑定
有点类似于python中的a,b = b,a
的超级加强版。
float x{};
char y{};
int z{};
std::tuple<float&,char&&,int> tpl(x,std::move(y),z);
const auto& [a,b,c] = tpl;
// a 指名指代 x 的结构化绑定;decltype(a) 为 float&
// b 指名指代 y 的结构化绑定;decltype(b) 为 char&&
// c 指名指代 tpl 的第 3 元素的结构化绑定;decltype(c) 为 const int
以上是最简单的绑定到数组,复杂的用到再说。
支持嵌套命名空间
嵌套命名空间定义:namespace A::B::C { ... }
等价于 namespace A { namespace B { namespace C { ... } } }
。这个还是挺有用的。不过命名空间一般没那么复杂。因为大家都喜欢用类包来包去。
using可以声明多个名称
字面意思
namespace X {
using ::f; // 全局 f 现在作为 ::X::f 可见
using A::g; // A::g 现在作为 ::X::g 可见
using A::g, A::g; // (C++17) OK:命名空间作用域允许双重声明
}
noexcept
作为函数声明的一部分
noexcept
使用更加自由,可以在typedef
等地方出现。
求值顺序修改
优化了”按顺序早于“里面的细枝末节的问题
lambda
支持捕捉*this
字面意思
struct S2 { void f(int i); };
void S2::f(int i)
{
[=]{}; // OK:默认以复制捕获
[=, &i]{}; // OK:以复制捕获,但 i 以引用捕获
[=, *this]{}; // C++17 前:错误:无效语法
// C++17 起:OK:以复制捕获外围的 S2
[=, this] {}; // C++20 前:错误:= 为默认时的 this
// C++20 起:OK:同 [=]
}
属性命名空间不必重复
[[using CC: opt(1), debug]] // 同 [[CC::opt(1), CC::debug]]
虽然是字面意思,但是我从没用过这个属性语法,不知道是干嘛的。
__has_include
语法
预编译器宏,功能就是字面意思。这个可以用来替代早期的程序在#include
的时候,为表示已经声明过了此文件而define
一个宏的写法。
库特性
不在此赘述,概括一下就是优化与新增STL。