走进C++11(十三) 变量之 -- 结构化绑定

 

其实C++11结构化绑定做的并不好,想要用结构化绑定的更好的版本要等到C++17。所以这里会提到C++17的用法。

 

简介

 

C++17语言上(语言特性,而不是标准库新特性)引入了一种结构化绑定的新特性,使用该特性可以利用auto同时声明多个不同类型的变量并即时从一个tuple-like对象得到赋值/初始化。
Structured binding不但可以使C++的代码更加简洁,而且似乎从语法上更贴近Python这种脚本语言了。另外,auto变量会在编译时推导出变量的类型,所以无需担心会有运行时效率的下降。而且,好像也并不会影响到编译效率,这一点尚未看到有实测。

 

在C++11的时候,如果要接收从函数返回的std::tuple对象,我们可以使用std::tie

 

举个例子:

 

#include <iostream>#include <tuple>std::tuple<int, double, std::string> f(){  return std::make_tuple(1, 2.3, "456");}int main(){  // C++17  auto [x, y, z] = f();  std::cout << x << ", " << y << ", " << z << std::endl;  //C++11  int a; double b, std::string c;  std::tie(a, b, c) = f();std::cout << a << ", " << b << ", " << c << std::endl;  return 0;}

 

结构化绑定声明 (C++17 起)

 

下面部分可以忽略。。。只是为了解释C++17的结构化绑定。

 

绑定指定名称到初始化器的子对象或元素。

类似引用,结构化绑定是既存对象的别名。不同于引用的是,结构化绑定的类型不必为引用类型。

 

定义

 

attr(可选) cv-autoref-运算符(可选) [ 标识符列表 ] = 表达式 ; (1)

attr(可选) cv-autoref-运算符(可选) [ 标识符列表 ] { 表达式 } ; (2)

attr(可选) cv-autoref-运算符(可选) [ 标识符列表 ] ( 表达式 ) ; (3)

attr -   任意数量的属性的序列

 

cv-auto -   可有 cv 限定的 auto 类型说明符,亦可包含存储类说明符 static 或 thread_local ;在 cv 限定符中包含 volatile 是被弃用的 (C++20 起)

ref-运算符    -    &或 && 之一

标识符列表   -   此声明所引入的各标识符的逗号分隔的列表

表达式   -   顶层没有逗号运算符的表达式(文法上为赋值表达式),且具有数组或非联合类之一的类型。若表达式 涉及任何来自 标识符列表 的名字,则声明非良构。

 

情况 1:绑定数组

 

标识符列表 中的每个标识符均成为指代数组的对应元素的左值。标识符的数量必须等于数组的元素数量。

每个标识符的被引用类型都是数组的元素类型。注意若数组类型 E 为 cv 限定的,则其元素亦然。

 

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]

 

情况 2:绑定元组式类型

 

表达式 std::tuple_size<E>::value 必须是良构的整数常量表达式,且标识符的数量必须等于 std::tuple_size<E>::value。

对于每个标识符,引入一个类型为“std::tuple_element<i, E>::type 的引用”的变量:若其对应初始化器是左值,则为左值引用,否则为右值引用。第 i 个变量的初始化器

 

  • 若在 E 的作用域中对标识符 get 按类成员访问进行的查找中,至少找到一个声明是首个模板形参为非类型形参的函数模板,则为 e.get<i>()

  • 否则为 get<i>(e),其中 get 只进行实参依赖查找,忽略非 ADL 的查找。

     

这些初始化器表达式中,若实体 e 的类型为左值引用(这仅在 ref-运算符 为 &,或为 && 且初始化器为左值时才发生),则 e 为左值,否则为亡值(这实际上进行了一种完美转发),i 是 std::size_t 的纯右值,而且始终将 <i> 解释为模板形参列表。

变量拥有与 e 相同的存储期。

然后该标识符变成指代与上述变量绑定的对象的左值。

第 i 个标识符的被引用类型为 std::tuple_element<i, E>::type。

 

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

 

情况 3:绑定到数据成员

 

E 的所有非静态数据成员必须都是 EE 的同一基类的直接成员,必须在指名为 e.name 时于结构化绑定的语境中是良构的。E 不能有匿名联合体成员。标识符的数量必须等于非静态数据成员的数量。

标识符列表 中的各个标识符,按声明顺序依次成为指代 e 的各个成员的左值的名字(支持位域);左值的类型是 cv T_i,其中 cvE 的 cv 限定符且 T_i 是第 i 个成员的声明类型。

第 i 个标识符的被引用类型cv T_i

 

struct S {    int x1 : 2;    volatile double y1;};S f(); const auto [x, y] = f(); // x 是标识 2 位位域的 const int 左值                         // y 是 const volatile double 左值

 

关注公众号获取更多信息:

 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值