广告位联系
返回顶部
分享到

C++11中转跳initializer_list实现的介绍

C语言 来源:互联网 作者:秩名 发布时间:2022-04-04 19:03:10 人浏览
摘要

1.初始化列表的实现 (1)当编译器看到{t1,t2tn}时便会生成一个initializer_listT对象(其中的T为元素的类型),它关联到一个arrayT,n。 (2)对于聚合类型,编译器会将arrayT,n内的元素逐一分

1.初始化列表的实现

(1)当编译器看到{t1,t2…tn}时便会生成一个initializer_list<T>对象(其中的T为元素的类型),它关联到一个array<T,n>。

(2)对于聚合类型,编译器会将array<T,n>内的元素逐一分解并赋值给被初始化的对象。这相当于为该对象每个字段分别赋值。

(3)对于非聚合类型。如果该类存在一个接受initializer_list<T>类型的构造函数,则初始化时会将initializer_list<T>对象作为一个整体传给构造函数。如果不存在这样的构造函数,则array内的元素会被编译器分解并传给相应的能接受这些参数的构造函数(比如列表中有2个元素的,就传给带2个参数的构造函数。有3个元素的,就传给带3个参数的构造函数,依此类推……)。

【实例分析】initializer_list<T>初体验

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

#include <iostream>

#include <vector>

#include <map>

#include <complex>

using namespace std;

//编译选项:g++ -std=c++11 test1.cpp -fno-elide-constructors

class Foo

{

public:

    Foo(int)

    {

        cout << "Foo(int)"<< endl;

    }

     

    Foo(int, int)

        cout << "Foo(int, int)"<< endl;

    Foo(const Foo& f)

        cout << "Foo(const Foo& f)"<< endl;

};

int main()

    Foo f1(123);

    Foo f2 = 123;   //先将调用Foo(int)将123转为Foo对象,再调用拷贝构造函数(后面这步可能被优化)

    Foo f3 = {123}; //生成initializer_list<int>,然后分解元素后,由于列表中只有1个元素,所以将其传给Foo(int)

    Foo f4 = {123, 321}; //生成initializer_list<int>,然后分解元素后,由于列表中有两个元素,所以将其传给Foo(int, int)

    //编译器会为以下花括号形成一个initializer_list<string>,背后有个array<string,6>

    //调用vector<string>的构造函数时,编译器会找到一个接受initializer_list<string>

    //的重载的构造函数。所有的容器均有这样的构造函数。在这个构造函数里会利用

    //initializer_list<string>来初始化。

    vector<string> city{"Berlin", "New York", "London", "Cairo","Tokyo", "Cologne"};

    //编译器会为以下花括号形成一个initializer_list<double>,背后有个array<double,2>。

    //调用complex<double>的构造函数时,array内的2个元素被分解并传给

    //Comlex<double>(double,double)这个带有两个参数的构造函数。因为comlex<double>并无

    //任何接受initializer_list的构造函数。

    complex<double> c{4.0, 3.0}; //等价于c(4.0, 3.0)

    return 0;

}

2. initializer_list<T>模板

//initializer_list<T>源码分析

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

#include <iostream>

template <class T>

class initializer_list

{

public:

    typedef T         value_type;

    typedef const T&  reference; //注意说明该对象永远为const,不能被外部修改!

    typedef const T&  const_reference;

    typedef size_t    size_type;

    typedef const T*  iterator;  //永远为const类型

    typedef const T*  const_iterator;

private:

    iterator    _M_array; //用于存放用{}初始化列表中的元素

    size_type   _M_len;   //元素的个数

     

    //编译器可以调用private的构造函数!!!

    //构造函数,在调用之前,编译会先在外部准备好一个array,同时把array的地址传入模板

    //并保存在_M_array中

    constexpr initializer_list(const_iterator __a, size_type __l)

    :_M_array(__a),_M_len(__l){};  //注意构造函数被放到private中!

    constexpr initializer_list() : _M_array(0), _M_len(0){} // empty list,无参构造函数

    //size()函数,用于获取元素的个数

    constexpr size_type size() const noexcept {return _M_len;}

    //获取第一个元素

    constexpr const_iterator begin() const noexcept {return _M_array;}

    //最后一个元素的下一个位置

    constexpr const_iterator end() const noexcept

    {

        return begin() + _M_len;

    } 

};

(1)initializer_list是一个轻量级的容器类型,内部定义了iterator等容器必需的概念,本质上是一个迭代器!

(2)对于std:: initializer_list<T>而言,它可以接收任意长度的初始化列表,但要求元素必须是同种类型(T或可转换为T)。

(3)它有3个成员函数:size()、begin()和end()。

(4)拥有一个无参构造函数,可以被直接实例化,此时将得到一个空的列表。之后可以进行赋值操作,如initializer_list<int> list; list={1,2,3,4,5};

(5)initializer_list<T>在进行复制或赋值时,它内部将保存着列表的地址保存在_M_array中,它进行的是浅拷贝,并不真正复制每个元素,因此效率很高。

【编程实验】打印初始化列表的每个元素

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

#include <iostream>

//打印初始化列表的每个元素

void print(std::initializer_list<int> vals)

{

    //遍历列表中的每个元素

    for(auto p = vals.begin(); p!=vals.end(); ++p){

        std::cout << *p << " ";

    }

     

    std::cout << std::endl;

}

//std::initializer_list<T>的浅拷贝。以下的返回值应改为std

//以下的返回值应改为std::vector<int>类型,而不是std::initializer_list<int>类型。

std::initializer_list<int> func(void)

    int a = 1;

    int b = 2;

    return {a, b}; //编译器看到{a, b}时,会做好一个array<int,2>对象(其生命

                   //期直至func结束),然后再产生一个initializer_list<int>

                   //临时对象,由于initializer_list<int>采用的是浅拷贝,当

                   //函数返回后array<int,2>会被释放,所以无法获取到列表中的元素!

int main()

    print({1,2,3,4,5,6,7,8,9,10});

    print(func());

    return 0;

/*测试结果:

e:\Study\C++11\7>g++ -std=c++11 test1.cpp

e:\Study\C++11\7>a.exe

1 2 3 4 5 6 7 8 9 10

*/

3.让自定义的类可以接受任意长度初始化列表

(1)自定义类中重载一个可接受initializer_list<T>类型的构造函数

(2)在该构造函数中,遍历列表元素并赋值给相应的字段。

【编程实验】自定义类的初始化列表

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

41

42

43

44

45

46

47

48

#include <iostream>

#include <map>

using namespace std;

class Foo

{

public:

    Foo(int a, int b)

    {

        cout << "Foo(int a, int b)" << endl;

    }

     

    Foo(initializer_list<int> list)

        cout << "Foo(initializer_list<int> list) : ";

         

        for(auto i : list){

            cout <<i<< " ";

        }

        cout << endl;

};

class FooMap

    std::map<int, int> content;

    using pair_t = std::map<int, int>::value_type;

    FooMap(std::initializer_list<pair_t> list)

        for(auto it = list.begin(); it!=list.end(); ++it){

            content.insert(*it);

             

            std::cout << "{" << (*it).first <<"," <<(*it).second <<"}" << " ";

        std::cout << std::endl;

int main()

    Foo f1(77, 5);     //Foo(int a, int b), a = 77, b = 5;

    //注意:由于定义了Foo(initializer_list<int> list)函数,以下3种方

    //式的初始化都会将{...}作为一个整体传递给该函数。如果没有定义该函

    //数,则由于该类是个非聚合类用{}初始化时,会调用构造函数来初始化。

    //但由于Foo类不存在3个参数的构造函数,所以f3那行会编译失败!

    Foo f2{77, 5};     //Foo(initializer_list<int> list)

    Foo f3{77, 5, 42}; //Foo(initializer_list<int> list)

    Foo f4 = {77, 5};  //Foo(initializer_list<int> list)

    FooMap fm = {{1,2}, {3,4},{5,6}};

    return 0;

}

/*测试结果:

e:\Study\C++11\7>g++ -std=c++11 test2.cpp

e:\Study\C++11\7>a.exe

Foo(int a, int b)

Foo(initializer_list<int> list) : 77 5

Foo(initializer_list<int> list) : 77 5 42

{1,2} {3,4} {5,6}

*/


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。

您可能感兴趣的文章 :

原文链接 :
相关文章
  • C++中类的六大默认成员函数的介绍

    C++中类的六大默认成员函数的介绍
    一、类的默认成员函数 二、构造函数Date(形参列表) 构造函数主要完成初始化对象,相当于C语言阶段写的Init函数。 默认构造函数:无参的构
  • C/C++实现遍历文件夹最全方法总结介绍

    C/C++实现遍历文件夹最全方法总结介绍
    一、filesystem(推荐) 在c++17中,引入了文件系统,使用起来非常方便 在VS中,可以直接在项目属性中调整: 只要是C++17即以上都可 然后头文件
  • C语言实现手写Map(数组+链表+红黑树)的代码

    C语言实现手写Map(数组+链表+红黑树)的代码
    要求 需要准备数组集合(List) 数据结构 需要准备单向链表(Linked) 数据结构 需要准备红黑树(Rbtree)数据结构 需要准备红黑树和链表适配策略
  • MySQL系列教程之使用C语言来连接数据库

    MySQL系列教程之使用C语言来连接数据库
    写在前面 知道了 Java中使用 JDBC编程 来连接数据库了,但是使用 C语言 来连接数据库却总是连接不上去~ 立即安排一波使用 C语言连接 MySQL数
  • 基于C语言实现简单学生成绩管理系统

    基于C语言实现简单学生成绩管理系统
    一、系统主要功能 1、密码登录 2、输入数据 3、查询成绩 4、修改成绩 5、输出所有学生成绩 6、退出系统 二、代码实现 1 2 3 4 5 6 7 8 9 10 11
  • C语言实现共享单车管理系统

    C语言实现共享单车管理系统
    1.功能模块图; 2.各个模块详细的功能描述。 1.登陆:登陆分为用户登陆,管理员登陆以及维修员登录,登陆后不同的用户所执行的操作
  • C++继承与菱形继承的介绍

    C++继承与菱形继承的介绍
    继承的概念和定义 继承机制是面向对象程序设计的一种实现代码复用的重要手段,它允许程序员在保持原有类特性的基础上进行拓展,增加
  • C/C++指针介绍与使用介绍

    C/C++指针介绍与使用介绍
    什么是指针 C/C++语言拥有在程序运行时获得变量的地址和操作地址的能力,这种用来操作地址的特殊类型变量被称作指针。 翻译翻译什么
  • C++进程的创建和进程ID标识介绍
    进程的ID 进程的ID,可称为PID。它是进程的唯一标识,类似于我们的身份证号是唯一标识,因为名字可能会和其他人相同,生日可能会与其他
  • C++分析如何用虚析构与纯虚析构处理内存泄漏

    C++分析如何用虚析构与纯虚析构处理内存泄漏
    一、问题引入 使用多态时,如果有一些子类的成员开辟在堆区,那么在父类执行完毕释放后,没有办法去释放子类的内存,这样会导致内存
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计