c++11之函数参数包展开

1.关于

本文略带总结性,参考:泛化之美--C++11可变模版参数的妙用
参数包展开方式有两种: 递归展开 和 逗号表达式展开。
本文代码并非全部来自参考文章,自己做了注释和修改。请以原文为准

2. 查询参数包的参数个数

用下面的函数可以实现查询参数包的个数

template<typename... Args>
unsigned int length(Args... args)
{
    return sizeof...(args);
}

调用

length(1, "hello", "c++", "11"); // 返回4,4个参数

3.递归展开

3.1 注意, 递归展开需要考虑爆栈的情况。 说到这里,ubuntu(linux) 默认栈大小8M(使用命令 ulimit -a查看), Win下,Visual Studio 默认栈大小1M(连接器->系统)。
3.2 需要两个函数:递归终止函数递归函数
3.3 一个例子,输出各个元素。函数参数为参数包的形式,使用递归展开.

// 1.递归终止函数
void print()
{
	;
}

// 2.递归执行函数
template<typename T, typename... Args>
void print(T head, Args... args)
{
	std::cout << head << (sizeof...(args) > 0 ? ", " : "");
	print(args...);
}

3.4 调用及执行结果

print(1, "hello", "C++", 11);

3.5 其执行过程

print(1, "hello", "C++", 11);
print("hello", "C++", 11);
print("C++", 11);
print(11);
print();

例子中,递归终止到第0参数截止。根据执行过程可知,终止函数可以改为1个参数,最后一个函数仅仅作为终止递归使用,终止递归改为1个参数的函数还可以提高性能(减少函数的调用)。

3.6 递归终止改为一个参数

// 1.递归终止函数
template<typename T>
void print(const T& t)
{
	std::cout << t << endl;
}

// 2.递归执行函数
template<typename T, typename... Args>
void print(T head, Args... args)
{
	std::cout << head << (sizeof...(args) > 0 ? ", " : "");
	print(args...);
}

同样的,执行上面的调用代码print(1, "hello", "C++", 11);,其执行过程如下

print(1, "hello", "C++", 11);
print("hello", "C++", 11);
print("C++", 11);
print(11);

3.7 再看一个递归求和的例子, 同样是使用参数包的形式

// 1.递归终止函数
template <typename T>
T sum(const T& t)
{
	return t;
}

// 2.递归函数
template <typename T, typename ... Args>
T sum(const T& head, const Args... args)
{
	return head + sum<T>(args...);
}

4.逗号表达式展开

  逗号表达式?了解一下

4.1 回到上面print的例子,改为逗号表达式

// 1.用作输出每个参数
template<typename T>
void show_arg(const T& t)
{
	std::cout << t <<std::endl;
}

// 2.用作展开参数包
template <typename ... Args>
void expand(const Args&... args)
{
	int arr[] = {(show_arg(args), 0)...}; /// (1)
}

代码中,(1)的逗号表达式为: (show_arg(args), 0)。先执行表达式1(show_arg(args)),再执行表达式2(0)。 使用调用代码expand(1, 2, 3, 4),(1)处的逗号表达式展开结果如下

int arr[] = { (show_arg(1), 0) , (show_arg(2), 0), (show_arg(3), 0), (show_arg(4), 0) };

而,第一个逗号表达式结果为0, 第二逗号表达式的结果为0, .... 最后一个逗号表达式展开后,逗号表达式的结果为0,所以(1)的代码最后是这样的:

int arr[] = {0, 0, 0, 0}; /// (2)

(2)的代码声明了一个int数组,数组有4个元素。 展开参数包的方式相当巧妙,比起递归,更加方便了。

4.2 使用lambda + 逗号表达式展开参数包
还是同样的例子,输出参数包元素。


template<typename Func, typename...Args>
void show_args(const Func &f, Args&... args)
{
	// 初始化列表,列表的类型为int, std::initializer_list是c++11引入的模板
	std::initializer_list<int>{(f(std::forward< Args>(args)), 0)...};
}

// 调用 
show_args([](const int & item) {std:: cout << item << ", ";  }, 1, 2, 3, 4); /// 输出: 1, 2, 3, 4,
posted @ 2020-10-22 10:00  mohist  阅读(5507)  评论(0编辑  收藏  举报