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编写一个错误信息输出函数使其可以作用于可变参数的形参

相关推荐
NAGNIP3 小时前
万字长文!回归模型最全讲解!
算法·面试
知乎的哥廷根数学学派4 小时前
面向可信机械故障诊断的自适应置信度惩罚深度校准算法(Pytorch)
人工智能·pytorch·python·深度学习·算法·机器学习·矩阵
txinyu的博客4 小时前
解析业务层的key冲突问题
开发语言·c++·分布式
666HZ6665 小时前
数据结构2.0 线性表
c语言·数据结构·算法
SmartRadio5 小时前
ESP32添加修改蓝牙名称和获取蓝牙连接状态的AT命令-完整UART BLE服务功能后的完整`main.c`代码
c语言·开发语言·c++·esp32·ble
实心儿儿6 小时前
Linux —— 基础开发工具5
linux·运维·算法
charlie1145141917 小时前
嵌入式的现代C++教程——constexpr与设计技巧
开发语言·c++·笔记·单片机·学习·算法·嵌入式
清木铎8 小时前
leetcode_day4_筑基期_《绝境求生》
算法
清木铎8 小时前
leetcode_day10_筑基期_《绝境求生》
算法
j_jiajia8 小时前
(一)人工智能算法之监督学习——KNN
人工智能·学习·算法