参数数目可变的函数模板或类模板。
可变数目的参数叫参数包(parameter packet),有两种:
- 模板参数包,有0个或多个模板参数。
- 函数参数包,有0个或多个函数参数。 ```cpp
// Args:模板参数包
// rest:函数参数包
template
//编译器会自行推断参数包中的参数数目和类型。 int i = 0; double d = 3.14; string s = “how now brown cow”;
foo(i, s, 42, d); // 包中有三个参数 void foo(const int&, const string&, const int&, const double&) ;
foo(s, 42, “hi”); // 包中有两个参数 void foo(const string&, const int&, const char[3]& );
foo(d, s); // 包中有一个参数 void foo(const double&, const string&);
foo(“hi”); // 空包 void foo(const char[3]&) ;
<a name="p1hVb"></a>## 可变参数(函数模板)我们学习过initializer_list实现的可变参数函数,但是这种只能函数参数数目可变,类型都一样。而可变参数模板可以做到类型和数目都可变。<br />我们首先定义一个名为print的函数,它在一个给定流上打印给定实参列表的内容。```cpp// 用来终止递归并打印最后一个元素的函数// 此函数必须在可变参数版本的print定义之前声明template<typename T>ostream &print(ostream &os, const T &t){return os << t; // 包中最后一个元素之后不打印分隔符}// 包中除了最后一个元素之外的其他元素都会调用这个版本的printtemplate <typename T, typename... Args>ostream &print(ostream &os, const T &t, const Args&... rest){os << t << ","; //打印第一个实参。return print(os, rest...); // 递归调用,打印其他实参。// rest...:包扩展,分解成元素,类似lua的unpack。}
包扩展
包扩展就是把参数包分解成构成的元素,分解结果就是一个逗号隔开的元素列表。
template<typename T, typename... Args>ostream &print(ostrearn &os, const T &t, const Args&... rest){os << t << ",";return print(os, rest...);// rest...:扩展rest成一个逗号隔开的参数列表,// 每个参数类型是const Arg&,Arg是模板可调用时推断}
C++包扩展还支持更复杂的模式。
template <typename... Args>ostream &errorMsg(ostream &os, const Args&... rest){// print(os, debug_rep(al), debug_rep{a2), ..., debug_rep(an)return print(os, debug_rep(rest)...);// print(os, debug_rep(al, a2, ..., an)print(os, debug_rep(rest...)); //错误:此调用无匹配函数}
转发参数包
在新标准下,我们可以组合使用可变参数模板与forward机制来编写函数,实现将其实参不变地传递给其他函数。
template <typename... Args>void fuck(Args&&... args){shit( std::forward<Args>(args)... ); // 将参数包完整传递给shit函数。// std::forward<Args>(args)...既扩展了函数参数包args也扩展了模板参数包Args}
