变量之(变长)列表初始化

关键词

std::initializer_list

解释

在 C++98/03 中的对象初始化方法有很多种,这无疑增大了学习难度。这中情况在C++11中终于得到解决。

先看看没有C++11的时候

    //初始化列表    int i_arr[3] = { 1, 2, 3 };  //普通数组    struct A    {        int x;        struct B        {            int i;            int j;        } b;    } a = { 1, { 2, 3 } };  //POD类型    //拷贝初始化(copy-initialization)    int i = 0;    class Foo    {        public:        Foo(int) {}    } foo = 123;  //需要拷贝构造函数    //直接初始化(direct-initialization)    int j(0);    Foo bar(123);        int data = 0; //赋值初始化    int data = {0}; //花括号初始化    int data(0); //构造初始化    int data{0}; //花括号初始化

这些不同的初始化方法,都有各自的适用范围和作用。最关键的是,这些种类繁多的初始化方法,没有一种可以通用所有情况。

为了统一初始化方式,并且让初始化行为具有确定的效果,C++11 中提出了列表初始化(List-initialization)的概念。

统一的初始化

举个小例子看看C++11变长初始化列表是怎么用的

#include <initializer_list>class MagicFoo{public:std::vector<int> vec;MagicFoo(std::initializer_list<int> list){for (std::initializer_list<int>::iterator it = list.begin();   it!= list.end(); ++it)vec.push_back(*it);}};int main(){   // after C++11MagicFoo magicFoo = {1, 2, 3, 4, 5};for (auto it : magicFoo.vec)  std::cout << it << std::endl;}

这里需要注意的是,虽然使用了等于号,但它仍然是列表初始化,因此,私有的拷贝构造并不会影响到它。

总结

C++11统一了所有初始化方式,都变成了下面的形式:

    Foo a3 = { 123 };    Foo a4 { 123 };

除了上面所述的内容之外,列表初始化还可以直接使用在函数的返回值上:

    struct Foo    {        Foo(int, double) {}    };    Foo func(void)   {        return { 123, 321.0 };    }

这里的 return 语句就如同返回了一个 Foo(123, 321.0)。

结构化绑定

简介

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

标识符列表 中的各个标识符,按声明顺序依次成为指代 e 的各个成员的左值的名字(支持位域);左值的类型是 cv T_i,其中 cv 是 E 的 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. 【C++grammar】结构化绑定

    目录 定义 1.用于原生数组的结构化绑定声明 2.用于std::array的结构化绑定声明 3.用于对象数据成员的结构化绑定声明 定义 结构化绑定声明是一个声明语句,意味着声明了一些标识符并对标识符做 ...

  2. c++17 to_chars、from_chars、if、结构化绑定

    c++17 to_chars.from_chars.if.结构化绑定 说明 std::to_chars std::from_chars 示例代码 输出 参考 说明 std::to_chars 通过成功 ...

  3. C2429 语言功能“结构化绑定“需要编译器标志“/std:c++17“

    C2429 语言功能"结构化绑定"需要编译器标志"/std:c++17" 1.问题 vs2019打开工程时报错:C2429 语言功能"结构化绑定&qu ...

  4. 列表初始化和赋值初始化的使用注意事项

    成员变量初始化方式有两种:列表初始化和赋值初始化.如下代码.但是这两种初始化表面上看着相同,但是用法和原理却并不相同.本篇博客主要讨论这两种初始化的使用方法和基本原理. class Test {pub ...

  5. 结构化、非结构化和半结构化数据 数据清洗

    结构化数据 **  结构化数据可以使用关系型数据库来表示和存储,如MySQL.Oracle.SQL Server等,表现二维形式的数据.可以通过固有键值获取相应信息.一般特点是:数据以行为单位,一行数 ...

  6. 现代c++之列表初始化/统一初始化

    #include <map> #include <string>class CDemo { public:int x;int y; };int main(void) {int ...

  7. 结构化数据、半结构化数据、非结构化数据

    1 概念 结构化数据 结构化数据可以使用关系型数据库来表示和存储,如MySQL.Oracle.SQL Server等,表现二维形式的数据.可以通过固有键值获取相应信息. 一般特点是:数据以行为单位,一 ...

  8. 结构化、非结构化和半结构化数据

    一直对结构化.非结构化和半结构化数据三个数据类型的概念有点模糊不清,今天特意花点时间网上查找了一番,继而,来此处进行一通总结. ** 结构化数据 ** 结构化数据可以使用关系型数据库来表示和存储,如M ...

  9. C语言中结构化数据(变量,指针,数组,字符串,结构体和联合)的内存表示

    目录 结构化数据表示 一.内存地址: 二.全局变量和局部变量的内存布局 三.数据在内存中的表示 四.数组在内存中的表示 五.字符串在内存中的表示 六.结构和联合在内存中的表示 结构化数据表示 一.内存 ...

最新文章

  1. 《Redis设计与实现》之第七章:压缩列表
  2. 【cmd】日期、时间格式化
  3. helm安装postgres_Helm 入门介绍 Kubernetes 上的包管理软件
  4. Android Ubuntu 安装问题FAQ
  5. vba打开txt文件_VBA基础入门(34)读取txt文本文件
  6. Python可以这样学(第三季:多线程与多进程编程)-董付国-专题视频课程
  7. 强命名保护DLL文件
  8. 6.11 如何在Excel自选图形中显示公式的数值 [原创Excel教程]
  9. Janusgraph索引
  10. 鸿蒙蕴含的哲理,苏轼最不该被忽视哲理名句:“人生到处知何似,应似飞鸿踏雪泥”...
  11. 安装chrome插件:FireShot
  12. JS去除输入文本的所有空格、逗号、换行符等空白字符
  13. 计算机品牌及介绍,【推广】电脑电源参数和品牌的介绍
  14. 如何删除计算机桌面多余的大e,教你删除属性里桌面多余背景图片
  15. OO第二单元电梯作业总结
  16. transformer模型的奥秘-学习笔记
  17. 地下水动力学--地下水水文学(持续更新)
  18. 杰理之KeyPage【篇】
  19. 爬虫(20)Scrapy知识补充+腾讯招聘案例+古诗文详情页+总结
  20. 写给电子工程师的,非常值得一看

热门文章

  1. uva 11995 I Can Guess the Data Structure!
  2. C\C++ 位域操作
  3. 什么叫「人的格局」?是否有必要培养大的格局或怎么培养?
  4. 牛客网(剑指offer) 第十九题 顺时针打印矩阵
  5. iOS之如何实现isEqual的重写
  6. LeetCode Algorithm 面试题 16.10. 生存人数
  7. Spark is not running in local mode, therefore the checkpoint directory must not be on the local……
  8. 教小学妹学算法:诺基亚引出的动态规划问题
  9. 深度学习——02、深度学习入门——卷积神经网络
  10. 大数据WEB阶段(十六)JavaEE三大 核心技术之监听器Listener