参数数目可变的函数模板或类模板。
可变数目的参数叫参数包(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; // 包中最后一个元素之后不打印分隔符
}
// 包中除了最后一个元素之外的其他元素都会调用这个版本的print
template <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
}