当前位置: 首页 > news >正文

C++11 --可变参数模版

文章目录

  • 1. 模版和函数参数包
  • 2. 展开参数包
  • 3. 在可变参数模版函数中使用递归

可变参数模版让你可以创建可以接受可变参数的函数模板和类模板

例如:要编写一个函数,它可以接受任意数量的参数,参数的类型只需是cout能够显示的即可,并将参数显示为用逗号分隔的列表。

int n = 14;
double x = 2.71828;
string mr = "hello world";
show_list(n, x);
show_list(x* x, '!', mr);

这里的目标是,定义show_list(),让让上述代码能够通过编译并生成如下输出:

14, 2.71828;

7.38905, !,hello world

要创建可变参数模版,需要理解几个要点:

  • 模版参数包
  • 函数参数包
  • 展开参数包
  • 递归

1. 模版和函数参数包

为理解参数包的工作原理,首先来看一个简单的模版函数,它显示一个只有一项的列表:

template<typename T>
void show_list(T value)
{cout << value << ",";
}

在上述定义中,右两个参数列表,模版参数列表只包含T,而函数参数列表只包含value。下面的函数调用将模版参数列表中的T设置为double,将函数参数列表中value设置为2.15.

show_list0(2.15);

C++11提供了一个用省略号标识的元运算符,能够声明标识模版参数包的标识符。模版参数包基本上是一个类型列表。同时还可以声明函数参数包的标识符。而**函数参数包基本上是一个值列表**。语法如下:

template<typename... Args>
void show_list1(Args... args)
{//
}

其中,Args是一个模版参数包,args是一个函数参数包,与其他参数名一样,可将这些参数包的名称指为任符合C++标识符规则的名称。Args 和 T 的差别在于,T 与 一种类型匹配,Args与任意数量(包括0)的类型匹配。

下面的程序调用:

show_list1('s', 80, "sweet", 4.5);

在这种情况下,参数包Args包含于函数调用的参数匹配类型:char、int、const char*、double.

下面的代码,指出value的类型为T

void show_list0(T value)

同样,下面的代码指出args 的类型为 Args

void show_list1(Args... args)

在这种情况下,函数参数包args包含值:‘s’, 80, “sweet”, 4.5

这意味着**函数参数包args包含的值列表 和 模版参数包Args包含的类型列表相匹配—无论是类型还是数量**。

2. 展开参数包

但是函数如何访问这些包的内容呢?索引功能不能使用,即不能通过Args[2]来访问包中的第3个类型。相反,可将省略号放在函数参数包名的右边,将参数包展开,例如:下面有缺陷代码:

template<typename... Args>
void show_list1(Args... args)
{show_list1(args...);
}

这是什么意思?有什么缺陷?有如下函数调用:

show_list1(5,'L',0.5);

这将把 5,‘L’,0.5 封装到args中。在该函数内部,下面的调用:

show_list1(args...);

将展开为:

show_list1(5,'L',0.5);

也就是说,args 被替换为3个存储在args中的值,因此,表示法 args… 展开为一个函数参数列表。

缺陷:该函数调用与原函数调用相同,因此它将使用相同的参数不断的调用自己,导致无限递归。

3. 在可变参数模版函数中使用递归

缺陷如何解决?

核心理念:将函数参数包展开,对列表中的第一项进行处理,再将余下的内容传递给递归调用,以此例推,直到列表为空

template<typename T,typename... Args>
void show_list3(T value, Args... args)

对于上述的定义:show_list3()的第一个参数决定了T 和value的值,而其他参数决定了Args 和args 的值。这让函数能够对value进行处理,如:显示它。然后递归调用show_list3()调用,并以args… 的方式将其它实参传递给它。每次递归调用都将显示一个值,并传递缩小了的列表。直到列表为空。

void show_list3()
{
}
template<typename T,typename... Args>
void show_list3(T value, Args... args)
{cout << value << ",";show_list3(args...);
}
int main()
{int n = 14;double x = 1.54;string mr = "hello world!";show_list3(n, x, mr);return 0;
}
/*输出结果:
14,1.54,hello world!,
*/

函数调用:show_list3(n, x, mr);

第一个实参T类型为:int,value为 14,其他二中类型(double,stirng)放入Args包中,而其他二个值(1.54,“hello world!”)放入args包中。

接下来调用:

show_list3(args...);

展开后:

show_list3(1.54,"hello world!");

前面说过,列表每次减少一项,这次T为:double,value为:1.54,而余下的一种类型和一个值分别被包装到Args和args中。下一次递归再将包缩小。最后,当args为空时,将调用不接受任何参数的show_list3(),导致结束。

优化:

  1. 去掉结果中最后一个逗号。
  2. 将值传递改为引用传递。—提高效率
void show_list3()
{
}
template<typename T> 
void show_list3(const T& value)
{cout << value << '\n';
}
template<typename T,typename... Args>
void show_list3(const T value, const Args... args)
{cout << value << ",";show_list3(args...);
}
int main()
{int n = 14;double x = 1.54;string mr = "hello world!";show_list3(n, x, mr);return 0;
}
/*输出结果:
14,1.54,hello world!
*/

全文完!


http://www.mrgr.cn/news/69687.html

相关文章:

  • kafka消费数据太慢了,给优化下
  • 关于我重生到21世纪学C语言这件事——指针详解(1)
  • 生产模式打包
  • 【MinIO】Python 运用 MinIO 实现简易文件系统
  • 287. 寻找重复数(二分查找)
  • 传奇996_19——常用函数
  • 【新书】掌握大语言模型:高级技术、应用、尖端方法和顶尖LLMs
  • 模型 长尾效应
  • 词嵌入方法(Word Embedding)
  • 月薪已炒到15w?强烈建议大家冲一冲设计新兴领域,工资高前景好,人才缺口极大!
  • 每个人都要懂的生活哲学养身哲学
  • 【设计模式】结构型模式(四):组合模式、享元模式
  • 在 Windows 安装 QT6.8 并用图形拉取界面 时间2024/11/10
  • 鸿蒙系统:智能生态的新纪元与开发者的新机遇
  • 牧神记开分9.7,2024新国漫巅峰出现了
  • 机器学习Housing数据集
  • 使用layui过程中的问题
  • mapreduce综合应用案例 — 气象数据清洗
  • 基于SpringBoot和Vue的公司文档管理系统设计与开发(源码+定制+开发)
  • LVGL UI设计神器助你高效开发嵌入式UI应用——v0.18.0发布(中)
  • SMOTE算法深度解析及代码实现
  • 「QT」几何数据类 之 QLine 整型直线类
  • UVC 输出视频格式修改和windows下数据分析
  • 【Linux系统编程】第四十四弹---从TID到线程封装:全面掌握线程管理的核心技巧
  • 树莓派(Raspberry Pi)产品介绍-硬件篇
  • ABC 379 D - Home Garden(队列+前缀和)