模板参数包是在C ++ 11中引入的。 今天,我们将利用它来编写fold
功能。 对于那些不知道fold(add, 1, 2, 3, 4, 5)
表达式是什么折叠函数的人,我们将输出(1 +(2 + (3 + (4 + 5)))) = 15
(左折)。 类似地,对于fold(mul, 1, 2, 3, 4, 5)
,我们将输出120。有关更多信息,请参见此处 。
让我们从代码开始。
下面的小片段实际上是我们所有功能的折叠功能。
// Base Case - Return the only remaining element.
template < typename Func, typename T>
T fold (Func f, T v) {
return v;
}
// General Case - Apply function to current element
// and folded output of the previous elements.
template < typename Func, typename T, typename ... Args>
T fold (Func f, T first, Args... args) {
return f(first,fold(f, args...));
}
我们可以通过以下方式调用fold函数。
// Sample function for testing.
template < typename T>
T add (T x, T y) { return x + y; }
int main () {
fold(add< double >, 1 , 2 , 3 );
}
这里发生的是,当我们在main中调用fold时,一般情况由编译器选择,并推导参数的类型。 Func
的类型为double (*)(double, double)
,而T为int
,标准所称的Args
参数包为{ int , int }
。 我们实质上从包装中剥离了第一个参数,并用它调用二进制函数,并将折算结果应用于包装的其余部分。 如果您对递归感到满意,您将很容易理解正在发生的事情。 我们正在创建类似于以下所示的表达式树。
因此,对于每个递归函数,我们都需要一个基本案例作为结尾。 在这种情况下,当我们只剩下函数和单个参数时,我们将返回该参数。 这为我们提供了基本值,并允许我们的树折叠计算输出。
要直观地看到我们假定的类型实际上是由编译器推导的类型,请尝试下面的代码。
# include <iostream>
// Base Case - Return the only remaining element.
template < typename Func, typename T>
T fold (Func f, T v)
{
std :: cout << "Base Function :" << __PRETTY_FUNCTION__ << "\n" ;
return v;
}
// General Case - Apply function to current element
// and folded output of the previous elements.
template < typename Func, typename T, typename ... Args>
T fold (Func f, T first, Args... args)
{
std :: cout << __PRETTY_FUNCTION__ << "\n" ;
return f(first, fold(f, args...));
}
// Sample functions for testing.
template < typename T>
T add (T x, T y) { return x + y; }
int main ()
{
fold(add< double >, 1 , 2 , 3 );
}
使用g ++编译器编译并执行此代码将为您提供帮助。
T fold(Func, T, Args ...) [with Func = double (*)(double, double); T = int; Args = {int, int}]
T fold(Func, T, Args ...) [with Func = double (*)(double, double); T = int; Args = {int}]
Base Function :T fold(Func, T) [with Func = double (*)(double, double); T = int]
这就是我们所期望的。 这是我们树的一种表示。
提示:在正确的位置使用constexpr
关键字,如果我们知道编译时的参数,则可以使编译器轻松地在编译时计算值。
From: https://hackernoon.com/folding-in-c-using-variadic-function-template-4o3c3ya1