3.16 含有可变参数的函数

3.16 含有可变参数的函数

用于编写函数参数不确定的函数,可以定义可变长度的形参表

3.16.1 含有可变参数的函数

C++标准中提供了两种主要的方法

  1. 如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型

    initializer_list

    initializer_list是一种标准库类型,用于表示某种特定类型的值的数组,该类型定义在同名的头文件中,也就是要include这个头文件(使用时需#include <initializer_list>

  2. 如果实参的类型不同,我们可以编写可变参数的模板

3.16.2 initializer_list提供的操作
initializer_list提供的操作 说明
initializer_list<T> lst; 默认初始化;T类型元素的空列表
initializer_list<T> lst{a, b, c...} lst的元素数量和初始值一样多;lst的元素是对应初始值的副本;列表中的元素是const
lst2(lst) lst2 = lst 拷贝或者赋值一个initializer_list对象但不拷贝列表中的元素;拷贝后原始列表和副本共享元素
lst.size() 列表中的元素数量
lst.begin() 返回指向lst首元素的指针
lst.end() 返回指向lst尾元素下一位置的指针
3.16.3 initializer_list的使用方法

initializer_list是一个类模板

使用模板时,我们需要在模板名字后面跟一对尖括号,括号内给出类型参数

C++ 复制代码
initializer_list<string> ls;//initializer_list的元素类型是string
initializer_list<int> li;//initializer_list的元素类型是int

initializer_list比较特殊的一点是,其对象中的元素永远是常量值,我们无法改变initializer_list对象中元素的值

简单来说:你可以读取initializer_list里的元素,但永远不能修改这些元素的值------哪怕你想在代码里直接赋值,编译器也会报错。下面用"通俗解释+代码示例"帮你彻底理解:

一、通俗理解

initializer_list想象成一个"只读的购物清单":

  • 你可以看清单上的每一项(读取元素);
  • 但你不能用笔把清单上的"苹果"改成"香蕉"(修改元素);
  • 若想改,只能重新写一份新清单(创建新的initializer_list),原清单永远不变。

二、代码示例:验证"无法修改元素"

下面的代码能直观体现这个特性,你可以复制到编译器中运行,看报错结果:

cpp 复制代码
#include <iostream>
#include <initializer_list>
using namespace std;

int main() {
    // 1. 创建一个initializer_list<int>,包含元素1、2、3
    initializer_list<int> lst = {1, 2, 3};

    // 2. 尝试修改第一个元素(编译器直接报错)
    // 错误写法:试图给常量元素赋值
    // lst.begin()[0] = 10;  // 这行代码会编译失败!

    // 3. 正确操作:只能读取元素,不能修改
    cout << "读取第一个元素:" << lst.begin()[0] << endl; // 输出1
    for (auto num : lst) {
        cout << num << " "; // 输出1 2 3(正常读取)
    }

    // 4. 若想"更新"元素,只能创建新的initializer_list
    initializer_list<int> new_lst = {10, 2, 3}; // 新清单,和原清单无关
    cout << "\n新列表第一个元素:" << new_lst.begin()[0] << endl; // 输出10
    return 0;
}

关键报错说明

如果你取消注释lst.begin()[0] = 10;这行,编译器会抛出类似错误:

复制代码
error: assignment of read-only location '* lst.std::initializer_list<int>::begin()'

翻译过来就是:"试图给只读的内存位置赋值"------本质是initializer_list的元素被编译器标记为const(常量),禁止写入操作。

三、为什么initializer_list要设计成"元素只读"?

这是C++标准的刻意设计,核心原因有2个:

  1. 简化底层实现initializer_list的拷贝/赋值不会复制元素(只是共享底层数组),如果允许修改元素,一个列表的修改会影响所有拷贝版本,引发不可控的bug;
  2. 语义匹配initializer_list的核心用途是"传递一组初始值"(比如给函数传可变参数),而非"存储可修改的数据集"------若需要可修改的集合,应该用vectorarray等容器。

四、和普通容器(如vector)的对比

用表格能更清晰看出差异:

操作 initializer_list vector(普通容器)
读取元素 ✅ 支持 ✅ 支持
修改元素(如v[0]=10 ❌ 禁止(编译报错) ✅ 支持
元素底层属性 const(常量) 普通变量(可读写)
核心用途 传递可变初始值 存储/修改数据集

总结

  1. initializer_list的元素是只读常量:只能读、不能改,修改会触发编译错误;
  2. 若需修改元素,不要用initializer_list,改用vectorarray等可读写容器;
  3. 这个设计是为了保证initializer_list的轻量性(拷贝共享元素)和语义安全性(避免意外修改)。

含有initializer_list形参的函数也可以同时拥有其他形参

3.16.4 initializer_list使用

在编写代码输出程序产生的错误信息时,最好统一用一个函数实现该功能,使得对所有错误的处理能够整齐划一,然而错误信息的种类不同,调用错误信息输出函数时传递的参数也会各不相同

使用initializer_list编写一个错误信息输出函数使其可以作用于可变参数的形参

相关推荐
郝学胜-神的一滴2 小时前
封装OpenGL的Shader相关类:从理论到实践
开发语言·c++·程序人生·游戏·图形渲染
步步为营DotNet2 小时前
深度解析.NET中属性(Property)的幕后机制:优化数据访问与封装
java·算法·.net
Swift社区2 小时前
LeetCode 454 - 四数相加 II
java·算法·leetcode
tokepson2 小时前
反向传播
深度学习·算法·ai·反向传播
Xの哲學2 小时前
Linux AQM 深度剖析: 拥塞控制
linux·服务器·算法·架构·边缘计算
艾醒2 小时前
大模型原理剖析——突破LLM效率瓶颈:多标记预测(MTP)技术深度解析与实战
算法
智驱力人工智能2 小时前
森林防火无人机火焰监测系统 构建“天空地”一体化智能防火体系 无人机火焰检测,支持红色火焰检测 城市高层建筑无人机火焰识别
人工智能·深度学习·opencv·算法·目标检测·无人机·边缘计算
多米Domi0112 小时前
0x3f第12天 0-1背包
python·算法·leetcode·动态规划
Bruce_kaizy2 小时前
c++图论————最短路之Floyd&Dijkstra算法
c++·算法·图论