一、可变参函数
含义:能够接收非固定个数参数的函数就是可变参数函数;
initializer_list标准库类型,用于处理可变参数问题,该类型能够使用的前提条件是,所有的实参类型相同
二、initializer_list (初始化列表)
如果一个函数,它的实参数量不可预知,但是所有参数的类型相同,我们就可以使用这个initializer_list类型的形参来接收。
initializer_list 是 C++ 11中提供的新类型,也是一个类模板。
我们把initializer_list理解成某种类型值得数组。这个类模板里指定的类型模板参数就是这个数组里保存的数据的类型。
包含头文件
#include <initializer_list> 或 #include <iostream>
initializer_list<int> array; //数组,元素类型是int,空列表(空数组)
initializer_list<int> array1 = { 10, 20, 30, 40, 50 };
注意:initializer_list对象中的元素永远是常量值,不能被改变。
1. begin()、end()、size()
void Func(initializer_list<string> array)
{
/*for (auto iter = array.begin(); iter != array.end(); ++iter)
{
cout << (*iter).c_str() << " ";
}*/
for (const auto& it : array) //用引用更节省性能
{
cout << it << " ";
}
cout << endl;
cout << array.size() << endl; //打印列表中元素数量
}
int main(int argc, const char* argv[])
{
Func({ "a", "b", "c" }); //若要往形参传递值的一个序列,必须用{}括起来
//其实C++ 11 将使用大括号{}初始化{初始化列表}作为一种比较通用的初始化方式,可用于很多的类型。
//函数initializer_list形参的函数也可以包含其他形参,互不影响。
return 0;
}
2. 拷贝和赋值
拷贝、赋值一个initializer_list对象,不会拷贝列表中的元素,原来对象和拷贝或者赋值出来的对象共享表中的元素。
initializer_list<string> myarray3 = { "aa", "bb", "cc" };
initializer_list<string> myarray4(myarray3); // 定义时初始化
initializer_list<string> myarray5;
myarray5 = myarray4; //赋值
3. 初始化列表做构造函数参数
class Test
{
public:
Test(initializer_list<int> list) {
int a = 1;
}
};
int main(int argc, const char* argv[])
{
Test test = { 10,20,30,40 }; //隐式类型转换 可加 explicit 防止隐式类型转换
Test test{ 1,2,3,4 };
return 0;
}
三、省略号形参(…) : 可变参数函数
这种省略形参式的可变参数函数,虽然参数数量不固定,但是函数的所有参数是存储在线性连续的栈空间中的。
而且带… 的可变参数函数必须至少要有一个普通参数,我们就可以通过这个普通参数来寻址后续的所有可变参数的类型以及值。
包含头文件:
#include <stdarg.h>
1. 整型类型参数
//可变参数函数
double Func(int num, ...) //num里面传进来的是可变参数的数量
{
va_list valist; //创建一个va_list类型变量
double sum = 0;
va_start(valist, num); //使valist指向起始的参数
for (int i = 0; i < num; ++i)
{
//遍历参数
sum += va_arg(valist, int); //参数2说明返回类型为int
}
va_end(valist); //释放valist
return sum;
}
int main(int argc, const char* argv[])
{
cout << Func(3, 10, 20, 30) << endl; //60
printf("value1 = %d, value2 = %d", 15, 17); //也是一种可变参函数
return 0;
}
2. 字符串类型参数
void Print(const char* msg, ...)
{
va_list list;
int num = atoi(msg);
va_start(list, msg);
int count = 0;
while (count < num)
{
char* p = va_arg(list, char*);
printf("第%d个参数是: %s\n", count, p);
count++;
}
va_end(list);
}
int main(int argc, const char* argv[])
{
Print("2", "Hello", "World");
return 0;
}
void Func(const char* arg...)
{
char str[1024] = { 0 };
va_list list;
va_start(list, arg);
vsprintf_s(str, sizeof(str), arg, list);
va_end(list);
cout << str << endl;
}
int main()
{
Func("要打印的字符串: %s, %s","Hello", "world"); //可以类似于日志输出打印到文件
return 0;
}
日志模块参考:C++ 日志模块打印
注意:
1. 至少有一个有效的形参,形参不能完全是…
2. …形参只能出现在形参列表最后一个位置。void Func(参数列表,…)
3. …之前的逗号可以省略
4. 如果有多个普通参数,那么va_start(va_list类型变量,参数类型),第二个参数必须绑…之前的那个参数
5. 一般这些可变参数类型是数值型或字符串型,其他类类型一般不能正常处理。
可参考:C 可变参数