CEO*_*ico 10 c++ recursion templates template-specialization variadic-templates
template<typename... ArgTypes>
int add(ArgTypes... args);
template<typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{
int sum = 0;
return t + add(args...);
}
template<> int add() {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如何添加更多乘法和减法等运算?这是什么template<> int add()意思?
谁能详细解释一下这个递归模板是如何工作的?
UPD:谢谢你们关于减法的事情,是的,减法不是可交换的,所以它并不适合这种递归模板。
use*_*601 10
这是我尝试的解释。
首先:
template<typename... ArgTypes>
int add(ArgTypes... args);
Run Code Online (Sandbox Code Playgroud)
这是起点。它说“存在一个名为的函数add,它接受零个或多个通用参数”。它不包含实现,因此它本身相当于对编译器的一种承诺,即这样的函数将存在。
然后我们有:
template<typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{
int sum = 0; // This line isn't doing anything!
return t + add(args...);
}
Run Code Online (Sandbox Code Playgroud)
这表示“这是一个被调用的函数add,它接受一个或多个通用参数”。它包括一个实现。该实现的一部分递归地调用add(args...)除第一个参数之外的所有参数(即零个或多个)。上面的第一个声明告诉我们存在这种情况。
如果 中至少有一个参数args,那么这一递归调用最终将再次调用完全相同的函数。args但是当包含零参数时会发生什么?我们需要函数的一个版本(特化)来处理这种情况,这是我们的第二个定义未处理的唯一情况。这就是第三个声明的来源:
template<> int add() {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
add这定义了一个名为0参数的函数。
所以,总而言之:
这是相当常见的递归可变参数模板。这个想法是我们使用递归
f(x0, x1, ..., xn) = f(f(x0, x1, ..., xn-1), xn) (1),
在你的样本中
add(x0, x1, ..., xn) = add(x0, x1, ..., xn-1) + xn。
可变参数模板提供了创建此类结构的简单且有用的方法。
首先,定义模板的通用签名(没有实现,因为我们从不使用通用形式)
template<typename... ArgTypes>
int add(ArgTypes... args);
Run Code Online (Sandbox Code Playgroud)
现在将模板函数专门用于具有至少一个参数的情况。我们使用递归来提取第一个参数并递归地调用自身,并将参数数量减少一个。
template<typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{
int sum = 0;
return t + add(args...); // recursive call without first arg
}
Run Code Online (Sandbox Code Playgroud)
为了停止递归,我们对空模板参数列表使用模板专门化(我们0在最后一步添加)。
template<> int add() {
return 0;
}
Run Code Online (Sandbox Code Playgroud)
对于乘法,您只需更改+为*,因为一般递归形式 (1) 在两种情况下都是相同的,并更改return 0为(在最后一步return 1乘以)。1
在减法情况下,递归 (1) 的一般形式不可用,因为a-b != b-a会产生歧义。还可以进行除法和其他非交换运算。您必须澄清操作顺序。