C++ 含有可变形参的函数

有时我们无法提前预知应该向函数传递几个实参。例如,我们想要编写代码输出程序产生的错误信息,此时最好用同一个函数实现该项功能,以便对所有的错误处理能够整齐划一。然而,错误信息的种类不同,所以调用错误输出函数时传递的实参也各不相同。

为了编写能处理不同数量实参的函数,c++11新标准提供了两种主要的方法:如果所有的实参类型相同,可以一个名为initializer_list的标准库类型;如果实参的类型不同,我们可以编写一种特殊的函数,也就是所谓的可变参数模板。

c++还有一种特殊的形参类型(即省略符),可以用它传递可变数量的实参,不过需要注意,此功能一般只用于与c函数交互的接口程序

1. initializer_list形参

如果函数的实参数量未知,但是实参类型均相同,我们可以用initializer_list类型的形参。initializer_list是一种标准库类型,用于表示某种特定类型的值的数组。initializer_list定义在同名的头文件中,它提供的操作如下所示。

initializer_list<T> lst; ——> 默认初始化,T类型元素的空列表;

initializer_list<T> lst{a, b, c...}; ——> lst初始化,lst的元素是const;

lst2(lst); lst2 = lst; ——> 拷贝初始化或者赋值初始化;

lst.size(); ——> 列表中的元素数量;

lst.begin(); ——> 列表首元素指针;

lst.end(); ——> 列表尾后元素指针;

类似vectorinitializer_list也是一种模板类型,定义initializer_list时,必须说明列表中所含元素的类型:

1
2
initializer_list<string> ls;   // initializer_list的元素类型是string
initializer_list<int> li; // initializer_list的元素类型是int

vector不同的是,initializer_list更加轻量,且initializer_list对象中的元素均为常量,不可更改。

1
2
3
4
5
6
7
8
9
10
11
void error_msg(initializer_list<string> ls)
{
for(auto it = ls.begin(); it != ls.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
}

error_msg({"functionX", "expected", "actual"}); // 调用
// output: functionX expected actual

2. 可变参数模板

待写。

3. 省略符形参

省略符形参是为了便于c++程序访问某些特殊的c代码而设置的,这些代码使用了名为varargs的c标准库功能。

注:省略符形参应该仅仅用于c和c++通用的类型。特别注意的是,大多数类类型的对象在传递给省略符形参时都无法正确拷贝。

示例程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int sum(int count, ...)
{
if (count <= 0)
{
return 0;
}
//为了实现可变参数列表,首先需要声明一个va_list类型的指针
// va_list类型是在cstdarg头文件里面定义的,该指针用来依次
//指向各个参数
// va_start是一个宏,用来初始化arg_ptr,使其指向列表的第一个
//参数,这个宏的第二个参数是sum函数参数列表省略号前得固定参
//数的名称,用来确定第一个参数的位置
va_list arg_ptr;
va_start(arg_ptr, count);

int CountSum = 0;
// va_arg是一个宏,返回arg_ptr指向的
//参数位置,并使arg_ptr递增来指向下一个参数值
// va_arg宏的第二个参数是需要统计的第
//一个参数的类型,如果类型不正确,
//程序也可能会执行,但得到的是无用的
//数据,arg_ptr将被错误地递增
for (int i = 0; i < count; ++i)
{
CountSum += va_arg(arg_ptr, int);
}
//将va_list类型的指针复位成空值
//就是清空可变参数列表
va_end(arg_ptr);
return CountSum;
}

sum1(5, 1, 2, 3, 4, 5); // 调用
// output: 15
  • valist 定义在cstdarg,stdarg.h头文件中,用来存储实参列表;
  • va_start(arg_ptr, count); 用来设置首个实参,表示取参数的时候从count的下一个参数开始(不包括count),因此,上例中第一个实参表示后面实参的个数;
  • va_arg(arg_ptr, int); 用来获取实参列表中的实参,int 是实参的类型。它从首个实参依次获取,将获取到的结果作为返回值返回;
  • va_end(arg_ptr); 表示用完arg_ptr,释放内存;

参考文献

《Primer c++》第5版 page 197;

c++ 含有可变形参的函数

c++ 可变参数详解

Author: wnxy
Link: https://wnxy.github.io/2022/05/09/cpp_func_with_variable_parameters/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.