当前位置: 首页 > news >正文

【C++11新章】一篇文章搞懂 std::initializer_list 模板类


🌈个人主页:聆风吟_
🔥系列专栏:C++11新章
🔖少年有梦不应止于心动,更要付诸行动。


文章目录

  • 一、initializer_list 是什么?
    • 1.1 定义
    • 1.2 必须包含的头文件
    • 1.3 标准定义简化版
  • 二、为什么需要它?
  • 三、核心特性
    • 3.1 元素类型必须完全相同
    • 3.2 只读不可修改
    • 3.3 轻量级包装,不拷贝数据
    • 3.5 临时对象
    • 3.5 支持范围 for、迭代器遍历
  • 四、基础用法示例
    • 4.1 普通函数接收
    • 4.2 实现求和函数
  • 五、让自定义类支持 {} 初始化
  • 六、核心成员函数
  • 七、特别注意
  • 📝全文总结

一、initializer_list 是什么?

1.1 定义

std::initializer_list是 C++11 提供的一个模板类,专门用来接收{}包裹的一组同类型数据,当作函数/构造函数的参数。简单说:

  • 我们写个{1,2,3,4}

  • 编译器会自动把它变成initializer_list<int>

  • 传给函数/构造函数使用

它就是让你的代码支持{}批量传值的核心工具。

1.2 必须包含的头文件

#include<initializer_list>

注意:部分编译器(如 GCC)在使用 STL 容器时会间接包含该头文件,但规范写法必须手动包含,否则可能编译失败。

1.3 标准定义简化版

template<classT>classinitializer_list{public:// 迭代器constT*begin()constnoexcept;constT*end()constnoexcept;// 元素数量size_tsize()constnoexcept;};


二、为什么需要它?

C++11 之前,给函数传一组值只能用数组、vector,写法繁琐:

voidfunc(intarr[],intlen){}// 麻烦,需传递数组+长度

有了initializer_list,直接用花括号列表传参,语法极简:

func({1,2,3,4});// 简洁!直接用 {} 传一组值

STL 容器(vector、map、list)能直接{}初始化,全靠它!



三、核心特性

3.1 元素类型必须完全相同

std::initializer_list只能存放同类型数据(如全int、全string),不支持 int+double+string 混合。

#include<initializer_list>usingnamespacestd;voidtest(autolist){}intmain(){// 错误:int + double + string 混合类型test({10,3.14,"hello"});return0;}

3.2 只读不可修改

initializer_list只读视图,仅支持读取元素,不支持修改:

  • 不能改值:*it = 100
  • 不能增删:无push_backerase等方法
#include<iostream>#include<initializer_list>usingnamespacestd;voidreadOnlyTest(initializer_list<int>list){// 读取:完全没问题cout<<"第一个元素:"<<*list.begin()<<endl;// 错误:表达式必须是可修改的左值// list.begin() = 100;}intmain(){readOnlyTest({1,2,3});return0;}

3.3 轻量级包装,不拷贝数据

这是initializer_list性能极高的原因:

  1. 我们写的{1,2,3}→ 编译器生成一个临时数组

  2. initializer_list不拷贝数组内容

  3. 它只存两个东西:

    • 指向临时数组首地址的指针

    • 元素大小(size)

相当于:它是数据的 “视图”,不是数据的 “副本”

#include<iostream>#include<initializer_list>usingnamespacestd;voidtest(initializer_list<int>list){// 拿到底层数组指针constint*p=list.begin();cout<<"指针地址:"<<p<<endl;cout<<"第一个元素:"<<*p<<endl;cout<<"元素个数:"<<list.size()<<endl;}intmain(){// 编译器创建临时数组 [1,2,3]// initializer_list 只存指针 + 大小,不拷贝数据test({1,2,3});return0;}

输出:

指针地址:0x... 第一个元素:1 元素个数:3

3.5 临时对象

{1,2,3}会被编译器生成临时的 initializer_list 对象,生命周期极短,当前语句执行完即销毁。

// 严重错误:返回临时对象的引用initializer_list<int>&badFunc(){return{10,20,30};}intmain(){// 悬空引用!数据已销毁autolist=badFunc();return0;}

3.5 支持范围 for、迭代器遍历

支持现代 C++ 两种遍历方式:

  1. 范围 for(最常用)
  2. 迭代器begin()/end()
#include<iostream>#include<initializer_list>usingnamespacestd;voidtraverse(initializer_list<int>list){cout<<"--- 范围 for 遍历 ---"<<endl;for(intx:list){cout<<x<<" ";}cout<<endl;cout<<"--- 迭代器遍历 ---"<<endl;for(autoit=list.begin();it!=list.end();++it){cout<<*it<<" ";}cout<<endl;}intmain(){traverse({10,20,30,40});return0;}

输出:

--- 范围 for 遍历 --- 10 20 30 40 --- 迭代器遍历 --- 10 20 30 40


四、基础用法示例

4.1 普通函数接收

#include<iostream>// 必须包含这个头文件#include<initializer_list>usingnamespacestd;// 函数参数:接收一组 int 数据voidprintNumbers(initializer_list<int>nums){// 1. 获取元素个数cout<<"元素个数:"<<nums.size()<<endl;// 2. 范围for遍历(最常用)for(intnum:nums){cout<<num<<" ";}cout<<endl;}intmain(){// 直接用 {} 传一组值!printNumbers({10,20,30,40});return0;}

输出:

元素个数:4 10 20 30 40

4.2 实现求和函数

intsum(initializer_list<int>nums){inttotal=0;for(intn:nums){total+=n;}returntotal;}// 使用方式sum({1,2,3});// 结果:6sum({10,20,30,40});// 结果:100


五、让自定义类支持 {} 初始化

给类添加参数为 initializer_list 的构造函数,即可像 vector 一样用{}初始化。

示例:自定义数组类,支持{1,2,3}初始化

#include<iostream>#include<initializer_list>#include<vector>usingnamespacestd;classMyArray{public:// 关键:initializer_list 构造函数MyArray(initializer_list<int>list){// 把列表数据存入容器for(intnum:list){my_data.push_back(num);}}// 打印函数voidshow(){for(intnum:my_data){cout<<num<<" ";}cout<<endl;}private:vector<int>my_data;};intmain(){// 像 vector 一样使用 {} 初始化!MyArray arr{1,2,3,4,5};arr.show();// 输出:1 2 3 4 5return0;}


六、核心成员函数

initializer_list接口极简,仅3个核心函数:

函数作用
begin()返回指向第一个元素的只读迭代器
end()返回指向最后一个元素下一位的只读迭代器
size()返回元素个数

常用操作:

std::initializer_list<int>list={10,20,30};// 获取大小list.size();// 访问第一个元素*list.begin();// 访问最后一个元素*(list.end()-1);// 遍历方式1:范围for(推荐)for(intx:list){...}// 遍历方式2:迭代器for(autoit=list.begin();it!=list.end();++it){...}// 遍历方式3:下标(不推荐,无operator[],用指针)constint*p=list.begin();intfirst=p[0];


七、特别注意

  1. 必须添加头文件
    #include<initializer_list>
  2. 元素只读,不可修改
    for(auto&x:list){x=10;// 报错!只读属性}
  3. 仅支持同类型数据传递
    func({1,3.14,"abc"});// 报错!类型必须完全一致


📝全文总结

  1. std::initializer_list是 C++11 用于接收{}包裹的一组同类型值的模板类
  2. 核心作用:让函数/自定义类支持{}传参、初始化
  3. STL 容器(vector、map、list)的列表初始化全部依赖它
  4. 核心特性:同类型、只读、轻量、编译器自动转换
  5. 自定义类优化:添加initializer_list构造函数,即可支持{}初始化

今天的干货分享到这里就结束啦!如果觉得文章还可以的话,希望能给个三连支持一下,聆风吟的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的最大动力!

http://www.gsyq.cn/news/1458549.html

相关文章:

  • 别再傻傻分不清:图解SCCB与I2C在时序上的关键三处不同(附示波器实测波形)
  • 别再被TB6600吓到了!用拇指大的A4988驱动42步进电机,51单片机/STM32/FPGA三平台代码实测
  • 告别寄存器恐惧:用Arduino+PlatformIO一步步调通SX1262 LoRa模块(附完整代码)
  • 中国人民大学研究团队打造的“多模态深度研究助手“
  • 微信小程序智慧物业系统源码包:支持云开发与本地部署,含报修投票、装修申请等完整功能
  • 【ST+梯形图混用实战:什么时候用什么,一张表说清楚】
  • 告别密码地狱:用Keycloak 18分钟搞定企业级单点登录与权限管理(Spring Boot实战)
  • 光伏电池片裂纹检测MATLAB工程包:含SVM模型、40组标注.mat图像与完整处理流程
  • 如何用PDFMathTranslate在30分钟内完成学术论文的精准翻译
  • 如何做微信投票链接,云帆投票小程序快速搭建教程 - 投票小程序
  • 别再死磕OLED了!用STM32F103驱动HMI串口屏,5分钟搞定交互界面(附完整代码)
  • M2.7工程化落地:面向研发工程师的AI工作流闭环模型
  • 手把手教你用Arduino UNO给ATmega168P烧录Bootloader(附USBasp备用方案)
  • 告别串口打印:用STM32 HAL库+DS18B20做个OLED屏显温度计(Keil工程开源)
  • CVE-2026-42945漏洞分析及复现
  • 实战演练:基于快马AI构建高可靠kafka订单事件驱动微服务系统
  • 彻底理清 B+ 树页分裂与页合并对大批量写入 MySQL分库分表与分区表的设计抉择 数据时吞吐量的影响路径
  • AD软件大电流布线必备:一招把Top层铺铜“变成”阻焊开窗,告别焊盘锡量不足的烦恼
  • 深入GL3224固件升级工具:如何手动添加Flash芯片支持(以Winbond W25Q16为例)
  • NarratoAI完整教程:三步掌握AI视频解说制作神器
  • AUTOSAR SPI实战避坑:同步调用Spi_SyncTransmit阻塞了CPU?试试异步Spi_AsyncTransmit提升效率
  • 用MATLAB批量生成卫星TLE文件:STK11自动化脚本实战(附完整代码)
  • 别再用BertModel直接喂给Chroma了!手写一个EmbeddingFunction解决HuggingFaceEmbeddings离线调用难题
  • Python 爬虫进阶技巧:批量解析 html 实体转义字符还原原始文本
  • 2026深度测评10款降AI率软件红黑榜!优缺点全曝光,达标率直接对标行业天花板
  • 用FPGA控制步进电机是种什么体验?从状态机到分频器,详解Verilog驱动A4988全流程
  • Apex Legends智能压枪助手终极指南:10分钟掌握精准射击
  • Spring AI Alibaba-ChatClient
  • MATLAB环境下可直接运行的KNN分类代码包:含主程序、核心函数与调用说明
  • 2026学术写作新范式:Gemini 3.1 Pro、Claude 3.5与GPT-4o协同润色实战指南