参数数目可变的函数模板或类模板。
可变数目的参数叫参数包(parameter packet),有两种:

  • 模板参数包,有0个或多个模板参数。
  • 函数参数包,有0个或多个函数参数。 ```cpp

// Args:模板参数包 // rest:函数参数包 template void foo (const T &t , const Args&… rest){ cout << sizeof … (Args) << endl; // 模板参数的数目 cout << sizeof … (args) << endl; // 函数参数的数目 }

//编译器会自行推断参数包中的参数数目和类型。 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]&) ;

  1. <a name="p1hVb"></a>
  2. ## 可变参数(函数模板)
  3. 我们学习过initializer_list实现的可变参数函数,但是这种只能函数参数数目可变,类型都一样。而可变参数模板可以做到类型和数目都可变。<br />我们首先定义一个名为print的函数,它在一个给定流上打印给定实参列表的内容。
  4. ```cpp
  5. // 用来终止递归并打印最后一个元素的函数
  6. // 此函数必须在可变参数版本的print定义之前声明
  7. template<typename T>
  8. ostream &print(ostream &os, const T &t){
  9. return os << t; // 包中最后一个元素之后不打印分隔符
  10. }
  11. // 包中除了最后一个元素之外的其他元素都会调用这个版本的print
  12. template <typename T, typename... Args>
  13. ostream &print(ostream &os, const T &t, const Args&... rest){
  14. os << t << ","; //
  15. 打印第一个实参。
  16. return print(os, rest...); // 递归调用,打印其他实参。
  17. // rest...:包扩展,分解成元素,类似lua的unpack。
  18. }

包扩展

包扩展就是把参数包分解成构成的元素,分解结果就是一个逗号隔开的元素列表。

  1. template<typename T, typename... Args>
  2. ostream &print(ostrearn &os, const T &t, const Args&... rest){
  3. os << t << ",";
  4. return print(os, rest...);
  5. // rest...:扩展rest成一个逗号隔开的参数列表,
  6. // 每个参数类型是const Arg&,Arg是模板可调用时推断
  7. }

C++包扩展还支持更复杂的模式。

  1. template <typename... Args>
  2. ostream &errorMsg(ostream &os, const Args&... rest){
  3. // print(os, debug_rep(al), debug_rep{a2), ..., debug_rep(an)
  4. return print(os, debug_rep(rest)...);
  5. // print(os, debug_rep(al, a2, ..., an)
  6. print(os, debug_rep(rest...)); //错误:此调用无匹配函数
  7. }

转发参数包

在新标准下,我们可以组合使用可变参数模板与forward机制来编写函数,实现将其实参不变地传递给其他函数。

  1. template <typename... Args>
  2. void fuck(Args&&... args)
  3. {
  4. shit( std::forward<Args>(args)... ); // 将参数包完整传递给shit函数。
  5. // std::forward<Args>(args)...既扩展了函数参数包args也扩展了模板参数包Args
  6. }