广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++11中跳转initializer_list实现分析
  • 451
分享到

C++11中跳转initializer_list实现分析

2024-04-02 19:04:59 451人浏览 薄情痞子
摘要

目录1.初始化列表的实现2. initializer_list<T>模板3.让自定义的类可以接受任意长度初始化列表1.初始化列表的实现 (1)当编译器看到{t1,t2&h

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>初体验

#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>源码分析

#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中,它进行的是浅拷贝,并不真正复制每个元素,因此效率很高。

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

#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;

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

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

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

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

#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;
}

到此这篇关于C++11中跳转initializer_list实现分析的文章就介绍到这了,更多相关C++11 initializer_list内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++11中跳转initializer_list实现分析

本文链接: https://www.lsjlt.com/news/144997.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++11中跳转initializer_list实现分析
    目录1.初始化列表的实现2. initializer_list<T>模板3.让自定义的类可以接受任意长度初始化列表1.初始化列表的实现 (1)当编译器看到{t1,t2&h...
    99+
    2022-11-13
  • C++11中跳转initializer_list怎么实现
    本篇内容介绍了“C++11中跳转initializer_list怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.初始化列表的实现(...
    99+
    2023-06-29
  • C++11中bind绑定器和function函数对象实例分析
    这篇文章主要介绍了C++11中bind绑定器和function函数对象实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++11中bind绑定器和function函数对象实例分析文章都会有所收获,下面我们...
    99+
    2023-07-02
  • Android中TextView实现部分文字可点击跳转
    本文实例为大家分享了TextView部分文字可点击跳转的具体代码,供大家参考,具体内容如下效果图:需求:每个item的文字都有两部分是连接可点击当然需要用到SpannableString和ClickableSpan。import andro...
    99+
    2023-05-30
    textview 点击跳转 roi
  • vue中详情跳转至列表页实现列表页缓存的示例分析
    小编给大家分享一下vue中详情跳转至列表页实现列表页缓存的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!提了一个需求,希...
    99+
    2022-10-19
  • 如何实现Web前端页面跳转并取到值的示例分析
    这篇文章将为大家详细讲解有关如何实现Web前端页面跳转并取到值的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。这个是A页面这是B页面通过点击A页面上的添加日志 跳...
    99+
    2022-10-19
  • 浅析如何在PHP中实现跳转并携带POST数据
    PHP是一种流行的服务器端脚本语言,用于构建动态的Web应用程序和网站。在PHP中,经常需要进行页面跳转以及跨页面传输数据。本文将讨论如何在PHP中实现跳转并携带POST数据。要理解如何在PHP中跳转并携带POST数据,首先需要了解HTTP...
    99+
    2023-05-14
    php post
  • C++11中模板隐式实例化与显式实例化的定义详解分析
    目录1. 隐式实例化2. 显式实例化声明与定义3. 显式实例化的用途1. 隐式实例化 在代码中实际使用模板类构造对象或者调用模板函数时,编译器会根据调用者传给模板的实参进行模板类型推...
    99+
    2022-11-13
  • c++中vector模拟实现的示例分析
    这篇文章将为大家详细讲解有关c++中vector模拟实现的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、vector是什么?vector是表示可变大小数组的序列容器,它也采用连续存储空间来存储...
    99+
    2023-06-14
  • css3中怎么实现一个可滑动跳转的分页插件
    css3中怎么实现一个可滑动跳转的分页插件,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。代码如下:<div class="pa...
    99+
    2022-10-19
  • C++中LeetCode实现单独数字的示例分析
    这篇文章主要介绍了C++中LeetCode实现单独数字的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。[LeetCode] 136.Single Number 单独的...
    99+
    2023-06-20
  • 如何进行C#中Dictionary的内部实现分析
    本篇文章为大家展示了如何进行C#中Dictionary的内部实现分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。了解Dictionary的开发人员都了解,和List相比,字典添加会慢,但是查找会比...
    99+
    2023-06-17
  • 亲自教你实现栈及C#中Stack源码分析
    定义 栈又名堆栈,是一种操作受限的线性表,仅能在表尾进行插入和删除操作。 它的特点是先进后出,就好比我们往桶里面放盘子,放的时候都是从下往上一个一个放(入栈),取的时候只能从上往下一...
    99+
    2022-11-12
  • 如何分析C# 加密中MD5和SHA1加密实现
    如何分析C# 加密中MD5和SHA1加密实现,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。对于C# 加密的认识,在C# 中可以很方便地进行MD5 和SHA1 加...
    99+
    2023-06-17
  • C++ STL容器中红黑树部分模拟实现的示例分析
    这篇文章主要介绍了C++ STL容器中红黑树部分模拟实现的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、红黑树的概念红黑树(Red Black Tree...
    99+
    2023-06-21
  • C语言中vector底层实现机制的示例分析
    这篇文章给大家分享的是有关C语言中vector底层实现机制的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、vector底层实现机制刨析通过分析 vector 容器的源代码不难发现,它就是使用 3 个迭...
    99+
    2023-06-25
  • 浅析C++模板类型中的原样转发和可变参数的实现
    目录原样转发的意义模板的可变参数总结原样转发的意义 前文我们实现了一个my_move函数,用来模拟stl的move操作,实现去引用的功能。其内部的原理就是通过remove_refer...
    99+
    2022-11-13
    C++ 原样转发 C++ 可变参数
  • CSS3中2D模拟实现摩天轮旋转效果的示例分析
    这篇文章给大家分享的是有关CSS3中2D模拟实现摩天轮旋转效果的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。先看效果图:由于上传的大小原因,只能录制成这种效果,原图是无...
    99+
    2022-10-19
  • C语言中实现朴素模式匹配算法的示例分析
    这篇文章给大家分享的是有关C语言中实现朴素模式匹配算法的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、什么是字符串的模式匹配?字符串模式匹配:在主串中找到与模式串相同的子串,并返回其所在位置。注意:①...
    99+
    2023-06-15
  • C语言详解分析进程控制中进程终止的实现
    目录进程退出的形式进程退出的几种方法进程退出的形式 进程退出的几种情况 正常退出(自愿,代码运行完其结果正确)错误退出(自愿,代码运行完其结果不正确)异常退出(非自愿,代码异常直接终...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作