[英]Recursive template explanation C++
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;
}
如何添加更多的运算,例如乘法和减法? template<> int add()
是什么意思?
谁能详细解释此递归模板如何工作?
UPD:谢谢你们关于减法,是的,减法不是可交换的,因此它实际上不适用于这种递归模板。
这是我的解释尝试。
首先:
template<typename... ArgTypes>
int add(ArgTypes... args);
这是起点。 它说:“存在一个名为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...);
}
这就是说“这里有一个叫做add
的函数,它需要一个或多个通用参数”。 它包括一个实现。 该实现的一部分以除第一个参数(即零个或多个)外的所有参数递归调用add(args...)
)。 上面的第一个声明告诉我们这是存在的。
如果args
中至少有一个参数,则此递归调用最终将再次调用完全相同的函数。 但是,当args
包含零参数时会发生什么呢? 我们需要函数的版本(专业化)来处理这种情况,这是第二个定义未处理的唯一情况。 那是第三个声明出现的地方:
template<> int add() {
return 0;
}
这定义了一个名为add
的函数,该函数需要零争论。
因此,总而言之:
谁能详细解释此递归模板如何工作?
我可以试试。
首先你有
template<typename... ArgTypes>
int add(ArgTypes... args);
这是一个可变参数模板函数声明:您声明存在一个add()
函数,该函数接收可变参数(零个或多个)数量的argumens。
注意:您声明但未定义函数。
第二:您声明和 定义
template<typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{
int sum = 0;
return t + add(args...);
}
一个不同的模板函数add()
,它们接收模板类型参数( t
)和可变参数模板列表( args...
)。
线
int sum = 0;
完全没用,因为声明了一个未使用的变量,但以下行
return t + add(args...);
完成返回t
和以下args...
之间的和( add(args...)
)的工作。
所以当args...
(因为更好的匹配)不为空且int add(ArgTypes... args)
时int add(T t, ArgTypes... args)
使用add(args...)
递归称为int add(T t, ArgTypes... args)
int add(ArgTypes... args)
当args...
是一个空列表时。
但是请记住,已声明但未定义int add(ArgTypes... args)
。
最后一点是
template<> int add() {
return 0;
}
这是在空列表的情况下第一个模板功能的完全专业化的定义(请记住,您不能对模板函数进行部分专业化,但可以对其进行完全专业化)。
离题建议:您不需要第一个模板功能; 您可以用更简单的非模板功能代替它。
您可以按以下方式重写代码
int add()
{ return 0; }
template <typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{ return t + add(args...); }
并按照Jarod42的建议,如果可以使用C ++ 17,则可以完全避免使用模板折叠进行递归
template <typename... ArgTypes>
int add (ArgTypes... args)
{ return (... + args); }
或使用auto
返回类型。
如何添加更多的运算,例如乘法和减法?
不知道减法(如何定义可变参数减法?),但是对于乘法,您可以使用类似的东西(但基本情况必须返回1
,而不是0
)
int mult ()
{ return 1; }
template <typename T, typename... ArgTypes>
int mult (T t, ArgTypes... args)
{ return t * mult(args...); }
或使用C ++ 17中的模板折叠,
template <typename... ArgTypes>
int mult (ArgTypes... args)
{ return (... * args); }
这是相当普遍的递归可变参数模板 。 这个想法是我们使用递归
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);
现在,针对至少具有一个参数的情况专门化模板功能。 我们使用递归提取第一个参数,然后递归调用自身,并将参数数量减少一个。
template<typename T, typename... ArgTypes>
int add(T t, ArgTypes... args)
{
int sum = 0;
return t + add(args...); // recursive call without first arg
}
为了停止递归,我们将模板专门化用于空模板参数列表(在最后一步添加0
)。
template<> int add() {
return 0;
}
对于乘法,只需将+
更改为*
,因为两种情况下通用递归形式(1)都相同,并且将return 0
更改为return 1
(在最后一步乘以1
)。
在减法情况下,递归(1)的一般形式不可用,因为ab != ba
,会引起歧义。 还可以进行除法和其他非交换运算。 您将必须澄清操作顺序。
递归有一个基本情况 。 因此,您可以将template<> int add()
作为涵盖T
的整数的基本情况的模板专业化。 当sizeof...(args)
为零时,将调用此方法。 请参阅此处的演示 。
对于乘法,您可以执行以下操作:
template<typename T, typename... ArgTypes>
int mult(T t, ArgTypes... args)
{
return t * mult(args...);
}
template<> int mult() {
return 1;
}
不过,我不确定您打算减法做什么。 我们可以有数字的总和(加法)和数字的乘积(乘法),但是没有像???那样的东西。 (减)数字。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.