C++17 新特性:结构化绑定
		
		目录
结构化绑定定义及用法
所谓"结构化绑定", 即将指定的名称绑定到初始化器的子对象或元素上。比如有如下结构体:
| 
					 1 2 3 4  | 
						struct Student {   int age;   std::string name; };  | 
					
那么有如下写法,直接把该结构体的成员绑定到新的变量名上:
| 
					 1 2  | 
						Student st{18, "Tom"}; auto [a, n] = st;  //auto a=n.age, auto n=s.name  | 
					
结构化绑定支持的方式:
| 
					 1 2 3  | 
						auto [ident-list] = expression; auto [ident-list] {expression}; auto [ident-list](expression);  | 
					
auto 前后可以使用 const alignas 和 & 修饰。
结构化绑定可以用在 数组(array)、类元组(tuple-like)和成员变量上(data members)。
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13  | 
						int tm[3] = {1949, 10, 1}; auto [y, m, d] = tm; std::cout << m << "/" << d << "/" << y << std::endl; std::map<int, std::string> mp = {{1, "Name"}, {2, "Age"}}; for (const auto& [k, v] : mp) {   std::cout << k << ": " << v << std::endl; } auto [it, rst] = mp.insert({1, "Type"}); if (!rst) {   std::cout << "Insert Error" << std::endl; }  | 
					
这么做的好处是使得代码结构更清晰,简洁易读。
细节及注意事项
1. 结构化绑定的类型
我们可以认为在结构化绑定的过程中, 其实有一个隐藏的匿名对象,就像是使用 expression 来初始化这个匿名对象的成员一样。
| 
					 1 2 3  | 
						auto e = st; auto a = e.age; auto n = e.name;  | 
					
需要特别注意的是: 结构化绑定时,修饰符是作用在匿名对象 (e) 上,而不是作用在绑定标识 (a or n) 上的
在如下代码中:
| 
					 1  | 
						const auto& [a, n] = st  | 
					
a 和 n 的类型为 int, 只有匿名对象 e 的类型是 const auto&
因此结构化绑定不会发生类型退化(decay)。在如下代码中,a 的类型是 int[3], a2 的类型退化为 int* .
| 
					 1 2 3 4 5 6 7  | 
						struct ST{     int arr[3]; }; ST st; auto [a] = st; auto a2 = a;   | 
					
2. 关于继承
对于继承类或结构体,结构化绑定则受到的限制:所有的成员必须在同一个类中定义。即在编译期结构化绑定必须能够完全访问类中的所有成员。
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19  | 
						struct Animal{     std::string name;     int age;         }; struct Dog: Animal {     int legs; }; struct Cat: Animal {     //no member }; Dog dog; auto [dn, da, dl] = dog;  //ERROR auto [dl2] = dog;  //ERROR Cat cat; auto [cn, ca] = cat;  //OK  | 
					
3. 其它
联合体不支持使用结构化绑定。
为类支持结构化绑定
要在一个类支持结构化绑定,需要在类中实现以下代码:
| 
					 1 2 3 4  | 
						#include <utility> std::tuple_size<type>::value //绑定标识的数量 std::tuple_element<idx, type>::type //标识 idx 的类型 auto get<idx>(ClassName){ return value; } //为 idx 返回值  | 
					
下面是一个实现:
对于一个类 Person:
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20  | 
						class Person {  public:   enum class Sex {     Male,     Female,   };   Person(int age, std::string name) : age_(age), name_(name) {}   Sex sex() const { return sex_; }   void set_sex(Sex sex) { sex_ = sex; }   int age() const { return age_; }   const std::string& name() const { return name_; }  private:   int age_;   std::string name_;   Sex sex_ = Sex::Male; };  | 
					
当我们想要为此类实现结构化绑定时,有以下方法需要实现
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40  | 
						template <> struct std::tuple_size<Person> {   static constexpr int value = 3;  //3个成员可以被绑定 }; // 偏特化每个绑定成员的类型 template <> struct std::tuple_element<0, Person> {   using type = int; }; template <> struct std::tuple_element<1, Person> {   using type = std::string; }; template <> struct std::tuple_element<2, Person> {   using type = Person::Sex; }; // 声明 get 方法 template <std::size_t> auto get(const Person& p); // 为每个 idx 实现 get 偏特化方法 template <> auto get<0>(const Person& p) {   return p.age(); } template <> auto get<1>(const Person& p) {   return p.name(); } template <> auto get<2>(const Person& p) {   return p.sex(); }  | 
					
之后可以使用结构化绑定:
| 
					 1 2  | 
						Person p(18, "Tom"); auto [age, name, sex] = p;  | 
					
注意这里我们只实现了拷贝在结构化绑定。对于引用的结构化绑定,我们还需要再实现一套。
| 
					 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21  | 
						Sex& sex() { return sex_; } int& age() { return age_; } std::string& name() { return name_; } template <std::size_t> decltype(auto) get(Person& p); template <> decltype(auto) get<0>(Person& p) {   return p.age(); } template <> decltype(auto) get<1>(Person& p) {   return p.name(); } template <> decltype(auto) get<2>(Person& p) {   return p.sex(); }  |