一、结构化绑定
如果搞过数据库的ORM映射,可能对这个所谓结构化绑定更好理解一些。一般来说,处理一个组合数据结构(数组、结构体、类等),当需要把其中的公有数据取出来时,一般是通过具体的位置操作或者相关属性操作取出来再进行相关的值的处理。这样以来,在一些纯数据类型或者说对数据进行全员操作时,就会显得代码很臃肿,不断重复着类似的动作。这和在数据结构中有大量数据需要初始化一样的道理,c++11以上的标准提供了初始化列表,那么同样也就会有这种取数据的操作,也就是结构化绑定。
结构化绑定可以理解成把组合数据结构和相关的变量进行绑定,快速方便的获得相关的数据值即“Binds the specified names to subobjects or elements of the initializer.”,它类似于引用,但不是引用类型。
参看细节如下网址:
https://en.cppreference.com/w/cpp/language/structured_binding
https://zh.cppreference.com/w/cpp/language/structured_binding
二、例程
类似这种结构化绑定的东西,说概念和理解不如来几个例程更清晰,先看一个简单的:
绑定到数组:
int a[2] = {1,2};
auto [x,y] = a; // 创建 e[2],复制 a 到 e,然后 x 指代 e[0],y 指代 e[1]
auto& [xr, yr] = a; // xr 指代 a[0],yr 指代 a[1]
绑定到元组:
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
绑定到数据结构:
struct S {
mutable int x1 : 2;
volatile double y1;
};
S f();
const auto [x, y] = f(); // x 是标识 2 位位域的 int 左值
// y 是 const volatile double 左值
说明一下,在c++20以前,不可以用Lambda 表达式捕获结构化绑定。
看一个综合的例子:
#include <set>
#include <string>
#include <iomanip>
#include <iostream>
int main() {
std::set<std::string> myset{"hello"};
for (int i{2}; i; --i) {
if (auto [iter, success] = myset.insert("Hello"); success)
std::cout << "插入成功。值为 " << std::quoted(*iter) << "。\n";
else
std::cout << "集合中已存在值 " << std::quoted(*iter) << "。\n";
}
struct BitFields {
int b : 4 {1}, d : 4 {2}, p : 4 {3}, q : 4 {4};
// C++20 :位域的默认成员初始化器
};
{
const auto [b, d, p, q] = BitFields{};
std::cout << b << ' ' << d << ' ' << p << ' ' << q << '\n';
}{
const auto [b, d, p, q] = []{ return BitFields{4, 3, 2, 1}; }();
std::cout << b << ' ' << d << ' ' << p << ' ' << q << '\n';
}
}
在这里有一个说明,在返回值中得到的绑定,不是绑定到返回值上而是一个新的拷贝对象。
三、总结
c++应用越是简单,越容易产生早期其它一些语言的现象,那就是会用但是完全不知道原理是什么。因此产生的后果是,一旦遇到异常,根本无从下手。所以学习c++还是要认真的把基础打好,深入到相关数据结构和算法的底层,踏实的把实现的原理搞清楚,知道每种用法的应用场景,利弊何在,根据实际的情况动态的取舍,而不是机械盲目的引入一些看上去高大上的东西。
要善于学习,善于钻研,善于解决问题,善于反思。