问题
当调用一个函数时,会遇到以下问题:
- 提前不知道传入的参数的数量;
- 也不知道传入参数的类型;
这种问题,在日志记录中最为明显:
- 记录的日志的信息可能有多条;
- 记录的日志的数据类型也可以是不同的;
实践解决方式
针对这些问题,在实践中,我一般都是封装为一个数据结构,在Java中使用JavaBeans。在C++中,也可以这么干,但是C++也提供了一些标准的操作方式,具体有以下几种:
- ellipsis …
- initializer_list
- variadic template
C++标准提供的解决方式
ellipsis …
在C++中,通过ellipsis实现可变参数。
- 这种方式是用于与C语言的代码进行交互,除此之外,不应该在C++语言中使用这种方式。
- 具体的实现方式通过C语言中的
varargs
完成; - 在函数声明中,可变参数只能是最后一个parameter,即如下两种形式之一:
void foo(param_list, ...){} void foo(...){}
- 另外,不同于基本的函数参数,对于传入函数的可变参数,不会进行类型检查;
initializer_list
特点
这种形式可以表示一组特定类型的参数,这些参数的类型唯一。
可以将initializer_list类比于
vector<T>
,也是一种template type,因此在定义该类型的变量时,需要指定类型,如下:initializer_list<string> ls;
但是,与
vector
不同的是,initializer_list
中的值均为const
,即无法修改;void func(initializer_list<int> il){ // 1. error, 返回的是pointer to const int int *p = il.begin(); // 2. ok const int *p = il.begin(); for(auto &a: il){ cout << a << endl; } cout << s << endl; }
当用1处的代码初始化 *p时,会报以下的错误:
error: invalid conversion from ‘std::initializer_list::const_iterator’ {aka ‘const int’} to ‘int’
使用2处的代码则ok。同样的,我们说initializer_list
中的数据为const,当使用for循环遍历时,使用如下代码,没有问题。其中的问题来自于auto关键字,参考这篇文章。 for(auto a: il){ a = 100; cout << a << endl; }
主要原因在于,这里发生了copy,即出现
auto a = il中的每一项
,虽然il中的数据为const,但是为top level const,在使用auto时,top level const被忽略。但是如下的代码:
for(auto &a: il){ a = 100; cout << a << endl; }
由于auto中用到了reference,此时top level const不会忽略,因此出现如下错误:
error: assignment of read-only reference ‘a’.
使用
initializer_list
参数的函数也可以定义其他的parameters,而且不要求initializer_list
参数是最后一个;void func(initializer_list<int> il, string s){ for(auto a: il){ cout << a << endl; } cout << s << endl; } initializer_list<int> il = {1 ,5 ,9}; func(il, "hello world");
相关操作
关于initializer_list的操作,与vector、数组有点类似,如下:
其中,可以利用这些API对initializer_list进行遍历:
- 基于for循环;
- 基于begin/end的指针操作;
void func(initializer_list<string> il) {
for (auto beg = il.begin(); beg != il.end(); ++beg){
cout << *beg << " " ;
}
}
variadic template
这部分是模板和泛型编程中的内容,C++ Primer - 16.4 Variadic Templates中有详细地介绍,鉴于还没学到模版编程,这里就先提一嘴,后续遇到后再展开。
参考资料
- C++ Primer - 6.2.6 Functions with Varying Parameters