c++17最新特性笔记
1.基本语言特性
这一部分介绍了 C++17中新的核心语言特性,但不包括那些专为泛型编程(即 template)设计的特性。
结构化绑定
结构化绑定允许你用一个对象的元素或对象初始化多个实例(第一眼感觉Python解包很像)
这有一个结构体
struct MyStruct
{
int i = 0;
std::string s;
};
MyStruct ms;
可以通过如下声明把该结构体的两个成员绑定到新的变量名
auto [u, v] = ms;
auto [u1, v1] {ms};
auto [u2, v2] (ms);
结构化绑定对于返回结构体或者数组的函数非常有用
MyStruct returnStruct()
{
return MyStruct{ 42,"Tom" };
}
我们可以把结构体中的成员变量分别赋值给两个新的局部变量
auto [id, name] = returnStruct();
还可以再进行操作
if (id>16)
{
/*...*/
}
结构化绑定还能大幅提高代码的可读性
例如:
不使用结构化绑定,对std::map
的遍历需要这么写
for (auto& elem : m1)
{
cout << elem.first << elem.second;
}
下面是使用结构化绑定:
for (const auto& [key,value] : m1)
{
cout << key << value << endl;
}
增加了代码的可读性(真的越来越现代了cpp)
1.1.1细说结构化绑定
绑定到一个匿名实体
auto [u, v] = ms;
这段代码实际上是做了如下操作:
auto e = ms;
... u = e.i;
... v = e.s;
这就意味这u,v是结构体内成员变量的拷贝(拷贝对象e的生命周期和结构化绑定一样长)
e 的生命周期和结构化绑定的生命周期相同,当结构化绑定离开作用域时 e 也会被自动销毁。另外,除非使用了引用,否则修改结构化绑定的变量并不会影响被绑定的变量:
MyStruct ms{42, "hello"};
auto [u, v] = ms;
ms.i = 77;
使用修饰符
我们可以在结构化绑定中使用修饰符,例如 const 和引用,这些修饰符会作用在匿名实体 e 上。通常情况
下,作用在匿名实体上和作用在结构化绑定的变量上的效果是一样的,但有些时候又是不同的(见下文)。
例如,我们可以把声明一个结构化绑定声明为 const 引用:
const auto& [u, v] = ms; // 引 用, 因 此u/v指 向ms.i/ms.s
这里,匿名实体被声明为 const引用,而u 和 v 分别是这个引用的成员 i 和s 的别名。因此,对ms 的成员的修
改会影响到 u 和 v 的值:
ms.i = 77;
//
影 响u的 值
std::cout << u;
//
打 印 出77
如果声明为非 const引用,你甚至可以修改对象的成员:
MyStruct ms{42, "hello"};
auto& [u, v] = ms;
// 被 初 始 化 的 实 体 是ms的 引 用
ms.i = 77;
// 影 响 到u的 值
std::cout << u;
// 打 印 出77
u = 99;
// 修 改 了ms.i
std::cout << ms.i;
// 打 印 出99
如果一个结构化绑定是引用类型,而且是对一个临时对象的引用,那么和往常一样,临时对象的生命周期会被
延长到结构化绑定的生命周期:
MyStruct getStruct();
...
const auto& [a, b] = getStruct();
std::cout << "a: " << a << '\n';
// OK
修饰符并不是作用在结构化绑定引入的变量名上
修饰符会作用在新的匿名实体上(即上文中的e
)而不会是u,v
上
const auto&[u,v] = ms;
u
和v
都不是引用,只有匿名实体e
是引用。u 和 v 分别是 ms 对应的成员的类型,只不过变成了const 的。根据我们的推导,decltype(u)
是 const int
,decltype(v)
是const std::string
。
结构体绑定适用的场景
原则上讲,结构化绑定适用于所有只有 public 数据成员的结构体、C风格数组和类似元组 (tuple-like)的对象:
• 对于所有非静态数据成员都是 public 的结构体和类,你可以把每一个成员绑定到一个新的变量名上。
• 对于原生数组,你可以把数组的每一个元素都绑定到新的变量名上。
• 对于任何类型,你可以使用 tuplelike API 来绑定新的名称,无论这套 API 是如何定义“元素”的。对于一个类型 type这套 API 需要如下的组件:
-
std::tuple_size<type>::value
要返回元素的数量。 -
std::tuple_element<idx, type>::type
要返回第 idx 个元素的类型。 -
一个全局或成员函数
get<idx>()
要返回第 idx 个元素的值。
注意要使用结构化绑定需要继承时遵循一定的规则。所有的非静态数据成员必须在同一个类中定义(也就是说,这些成员要么是全部直接来自于最终的类,要么是全部来自同一个父类):
struct B
{
int a = 0;
int b = 3;
};
struct B1 :B
{
int c = 4;
};
auto [x, y] = B{};//OK
auto [x1, y1, z1] = B1{};//ERROR
原生数组
int arr[] = { 1,2 };
auto [a1, b1] = arr; //按值拷贝
std::pair, std::tuple 和 std::array