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

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.kler.cn/a/387599.html

相关文章:

  • WPF中MVVM工具包 CommunityToolkit.Mvvm
  • 解决C盘空间不足的三种方案
  • Elasticsearch中什么是倒排索引?
  • aws xray通过设置采样规则对请求进行过滤
  • windows下qt5.12.11使用ODBC远程连接mysql数据库
  • 分布式和并发模型的比较和讨论记录
  • 解锁视频 “声” 意,尽在“云剪辑”
  • ElfBoard技术贴|如何完成FRP内网穿透
  • 深度学习之卷积神经网络(CNN)
  • AndroidStudio-文本显示
  • dell服务器安装ESXI8
  • 架构零散知识点
  • git 多账号配置
  • svgicon大小问题(简单记录
  • 数据分析驱动的市场预测:民锋量化技术的创新探索
  • Visio使用教程
  • Kafka 可观测性最佳实践
  • wps怎么算出一行1和0两种数值中连续数值1的个数,出现0后不再计算?
  • 企业IT架构转型之道:阿里巴巴中台战略思想与架构实战感想
  • 【提效工具开发】Python功能模块执行和 SQL 执行 需求整理
  • python可视化将多张图整合到一起(画布)
  • 三次权重函数
  • web——sqliabs靶场——第二关
  • 基于SpringCloud+Vue的社区服务系统 (含源码数据库)
  • 【AI】【提高认知】卷积神经网络:深度学习与计算机视觉的核心驱动力
  • HTTP 和 HTTPS 的区别 - 2024最新版前端秋招面试短期突击面试题【100道】