当前位置:   article > 正文

C++可变参数模板_c++ 可变参数模板

c++ 可变参数模板

在C++中,我们可以使用可变参数模板函数来实现接受可变个数参数的函数。

可变参数模板函数语法

可变参数模板函数的基本语法如下:

template <typename T,typename... Args>
返回值类型 函数名(T first, Args... args) {
  // 函数体
}
  • 1
  • 2
  • 3
  • 4

其中T 是命名参数的类型,Args...表示参数包,args是参数包的名字。在函数体中,我们可以通过args来访问传递进来的参数。

处理参数包的方法

递归展开参数包

可以使用递归来逐个访问参数包中的每个元素:

template<typename T>
void Print(const T& str){//特化
	cout << str << endl;
}

template <typename T, typename... Args>
void Print(T& first, Args&&... args) {
  cout << first; 
  Print(forward<Args>(args)...);//完美转发
}
//上面的模板也可以不用完美转发
//void Print(T& first, Args... args) {
//  cout << first; 
//  Print(args...);
//}

int main(){
	Print("hello ");
	Print("hello ", "你好 ");
	Print("hello ", "你好 ","666");
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

递归展开参数包可以访问每个参数,但代码较复杂。假设我们执行最下面的Print(“hello”,“你好”,“666”),程序的执行逻辑是:调用模板函数,hello传给first,后面两个实参传给可变参数包

输出结果:
在这里插入图片描述

使用std::tuple及std::get函数来获取参数

将参数包存入std::tuple,然后用std::get访问每个元素:

template <typename... Args>
void print(Args... args) {
  auto t = make_tuple(args...);
  
  cout << get<0>(t) << endl;
  cout << get<1>(t) << endl;
  // ...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这种方法代码简洁,但需要知道每个参数的类型和序号。

示例

#include <iostream>
#include <tuple>

template <typename... Args>
void parse(Args... args) {
	auto tup = make_tuple(args...);
	cout << get<3>(tup) << endl;
	//get不能这么用,get中的<>里面的值得是const的
	//auto tup = make_tuple(args...);
    //for(auto i=1;i<get<0>(tup);i++){
    //    cout << get<i>(tup) << endl;
    //}   
}

int main() {
	parse(1, 2, 3, 4, 5);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

程序输出:

4
  • 1

逗号表达式展开参数包

这种展开参数包的方式,不需要通过递归终止函数,是直接在展开函数的函数体中展开的, printarg不是一个递归终止函数,只是一个处理参数包中每一个参数的函数。这种就地展开参数包的方式实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。展开函数中的逗号表达式:(printarg(args), 0),也是按照这个执行顺序,先执行printarg(args),再得到逗号表达式的结果0。同时还用到了C++11的另外一个特性——初始化列表,通过初始化列表来初始化一个变长数组, {(printarg(args), 0)...}将会展开成((printarg(arg1),0),(printarg(arg2),0), (printarg(arg3),0),...),最终会创建一个元素值都为0的数组int arr[sizeof...(Args)]。由于是逗号表达式,在创建数组的过程中会先执行逗号表达式前面的部分printarg(args)
打印出参数,也就是说在构造int数组的过程中就将参数包展开了,这个数组的目的纯粹是为了在数组构造的过程展开参数包.

template <class T>
void PrintArg(T t){
	cout << t << " ";
}
//展开函数
template <class ...Args>
void ShowList(Args... args){
	int arr[] = { (PrintArg(args), 0)... };
	cout << endl;
}
int main(){
	ShowList(1);
	ShowList(1, 'A');
	ShowList(1, 'A', std::string("sort"));
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

直接将参数包作为实参传递

在下方代码中,fun_函数直接讲参数包传递给fun,fun函数则会讲args参数包依次展开对应其形参

void fun(int a, char b)
{
	cout << a << b << endl;
}

template <class ...Args>
void fun_(Args ...args)
{
	fun(args...);
}
int main()
{
	fun_(3,'a');
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/576955
推荐阅读
相关标签
  

闽ICP备14008679号