当前位置:   article > 正文

C++ 可变参数模板

c++ 可变参数模板

可变参数模板是C++11引入的特性,它能够创建可变数量参数的模板函数和模板类。这一特性让我们可以编写出更加灵活和通用的代码。

可能光这样子说,没有感觉,那就举一个简单的例子吧,假设现在有一个需求:

要编写一个函数,它可以接收任意数量的参数,并且参数类型只需要是cout能够显示的即可。 

从需求来看,传进函数的参数数量不固定,并且类型的顺序也不固定,我们不可能定义很多个打印函数来做到这个需求,因为组合的情况太多太多了。

这种情况下,用可变参数模板就可以解决这个问题。在后面的部分,我将用上面这个例子贯穿全文来说明可变参数模板,旨在说明可变参数模板这个技术。

一. 模板参数包和函数参数包

       C++11提供了一个用省略号(...)表示的元运算符,用这个运算符来表示模板参数包和函数参数包的标识符,模板参数包基本上是一个类型列表,函数参数包基本上是一个值列表,语法如下:

                       

       模板参数包Args与任意数量(包括零)的类型匹配,函数参数包args所包含的值列表与模板参数包所含的类型列表(无论是类型还是数量)匹配。

上面那个打印函数参数的那个例子,我们可以声明为如下这样:

  1. template<typename... Args>
  2. void show_list(Args... args) {
  3. ......
  4. }

如果现在我们需要这样调用它:

show_list('I', "love", 2024);
  • 模板参数包Args包含的类型就是:char、const char*、int。
  • 函数参数包args对应包含的值就是:'I'、 "love"、2024。

二.展开参数包

那模板参数包和函数参数包的内容该如何访问呢?索引功能在这里无法使用,即不能使用类似于Args[1]来访问包中的第二个参数类型;

1. 递归方式访问

函数参数包的话,可以将省略号放在其右边(即:args...),将参数包展开。采用递归的方式访问:对参数列表里的第一项进行处理,再将余下的内容传递给递归调用,直到列表为空。 

还是关于打印参数这个例子,看一下如何展开这个函数参数包并打印。和常规递归一样,确保递归终止很重要, 最后写出来的代码如下:

  1. // 递归终止条件
  2. void show_list() {};
  3. template<typename T, typename... Args>
  4. void show_list(T value, Args... args) {
  5. // 打印第一个参数,然后递归打印剩余参数
  6. cout << value << " ";
  7. show_list(args...);
  8. };
  9. void test01() {
  10. show_list('I', "love", 2024);
  11. return;
  12. };

在上面的示例中,show_list函数使用了可变参数模板。当调用show_list函数时,它会递归地打印每个参数,直到没有剩余参数为止。 这里有一个技巧就是函数模板的头改为了:

  1. template<typename T, typename... Args>
  2. void show_list(T value, Args... args) {}

 show_list()的第一个实参决定了T和value的值,而其他实参决定了Args和args的值。这让函数能够对value进行处理;然后递归调用show_list(),并以args...的方式将其他实参传递给它。每一次递归调用处理一个值,并且传递缩短了的列表,直到列表为空为止:

  1. 当调用了show_list('I', "love", 2024),第一个实参会使得T为char,value为‘I’;另外两个类型(string和int)将放入Args包中,对应的另外两个实参将放入args包中。
  2. 接下来show_list(args...):  考虑到args...的展开作用,这一步与如下代码等价:show_list("love", 2024)。至此参数列表减少了一项
  3. 再按上述规则依次类推,直到参数列表为空为止。

最后函数调用过程就如下面这张图所示

2. 折叠表达式展开 

折叠表达式展开的方式是到了C++ 17才提供的,C++ 11是不支援的。折叠表达式示例如下:

  1. template<typename... Args>
  2. void show_list(const Args&... args) {
  3. (cout << ... << args)<<endl;
  4. };

 但是打印时各个参数都粘在了一起,不好看。可以利用逗号表达式控制一下格式打印,如下所示:

  1. template<typename... Args>
  2. void show_list(const Args&... args) {
  3. (cout << ... << (cout<<args," ")) << endl;
  4. };

3. 其他方式

还有其他的展开参数包的方式,不过这里就不多做介绍了,可以参考其他的博客:

 c++可变参数模板展开参数包_c++ 模板形参包的展开-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/577040
推荐阅读
相关标签
  

闽ICP备14008679号