当前位置: 首页 > 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.jsqmd.com/news/947045/

相关文章:

  • GLM-5.1代码修复能力深度解析:AST引导解码与真实PR数据训练
  • 莫瑶教育AI全域课程:重构AI时代竞争力,从职场提效到商业变现的系统化成长方案 - 全国职业学校推荐官
  • Python自动化办公新思路:定时抓取通达信财务数据并关机,解放你的下班时间
  • MHmarkets迈汇平台:把服务体系做到位——细节梳理与提示整理
  • STAR模型:零样本跨模态网站指纹识别技术解析
  • 从 ChatMemory 到 Mem0:我终于理解了 Agent 里的“记忆”到底是什么
  • 通达信缠论插件:3分钟掌握专业级K线分析技术
  • 青少年匹克球拍有哪些销售厂家,哪家更值得选择?
  • 别再傻傻分不清:图解SCCB与I2C在时序上的关键三处不同(附示波器实测波形)
  • 摆脱无效内卷,做好项目管理的实用思路
  • C语言写的学生成绩与档案管理工具(VC6工程+可执行文件+详细文档)
  • C++编写的车辆轨迹跟踪MPC控制器源码包:含编译脚本、实测赛道数据与算法推导文档
  • Halcon 23.11实战:用自带果汁瓶图片5分钟搞定你的第一个深度学习缺陷检测模型
  • 别再被TB6600吓到了!用拇指大的A4988驱动42步进电机,51单片机/STM32/FPGA三平台代码实测
  • QQ空间历史说说一键导出终极指南:免费获取你的青春回忆
  • 告别重复造轮子:用快马高效生成unet变体,加速你的图像分割模型迭代
  • 华为AI眼镜深度解析:31克无感终端与豆包AI引擎的技术突破
  • Matlab VOF模拟二维溃坝:投影法求解中的密度插值与体积分数矫正避坑指南
  • 告别寄存器恐惧:用Arduino+PlatformIO一步步调通SX1262 LoRa模块(附完整代码)
  • CAPL脚本数据处理避坑指南:整型数组与Hex字符串互转的实战函数库
  • 中国人民大学研究团队打造的“多模态深度研究助手“
  • 6.LangChain-2
  • 告别裸机延时!在STM32CubeIDE里用HAL库定时器给DS18B20写个优雅的驱动
  • 【ST+梯形图混用实战:什么时候用什么,一张表说清楚】
  • LoRa模块功耗优化实战:让SX1261在电池供电下多跑一年(含睡眠、CAD唤醒配置)
  • 微信小程序智慧物业系统源码包:支持云开发与本地部署,含报修投票、装修申请等完整功能
  • 零基础本地运行Gemma 4B:Ollama+GGUF极简部署指南
  • iOS 开发效率工具有哪些?在一次页面调试改了17次代码之后,我总结出的工具
  • Claude Code 完全实战指南 - 第一章:安装配置与本地大模型
  • 车载以太网之要火系列 - 番外篇5:DDS学完回头看,入门容易精通难