如何编写可变模板递归函数
How to write a variadic template recursive function?
我正在尝试编写一个可变模板constexpr
函数,该函数计算给定模板参数的总和。这是我的代码:
template<int First, int... Rest>
constexpr int f()
{
return First + f<Rest...>();
}
template<int First>
constexpr int f()
{
return First;
}
int main()
{
f<1, 2, 3>();
return 0;
}
不幸的是,在尝试解析f<3,>()
调用时,它没有编译报告错误消息error C2668: 'f': ambiguous call to overloaded function
。
我还尝试更改我的递归基本情况,以接受0模板参数,而不是1:
template<>
constexpr int f()
{
return 0;
}
但此代码也不进行编译(消息error C2912: explicit specialization 'int f(void)' is not a specialization of a function template
(。
我可以提取第一个和第二个模板参数,使其编译并工作,如下所示:
template<int First, int Second, int... Rest>
constexpr int f()
{
return First + f<Second, Rest...>();
}
但这似乎不是最好的选择。因此,问题是:如何以优雅的方式编写此计算?
UP:我也试着把它写成一个单独的函数:
template<int First, int... Rest>
constexpr int f()
{
return sizeof...(Rest) == 0 ? First : (First + f<Rest...>());
}
这也不起作用:error C2672: 'f': no matching overloaded function found
。
您的基本情况是错误的。您需要一个空列表的案例,但正如编译器所建议的,您的第二次尝试不是有效的模板专用化。为零参数定义有效实例化的一种方法是创建一个接受空列表的重载
template<class none = void>
constexpr int f()
{
return 0;
}
template<int First, int... Rest>
constexpr int f()
{
return First + f<Rest...>();
}
int main()
{
f<1, 2, 3>();
return 0;
}
编辑:为了完整起见,也是我的第一个答案,@alexeykuzmin0通过添加条件:来修复
template<int First=0, int... Rest>
constexpr int f()
{
return sizeof...(Rest)==0 ? First : First + f<Rest...>();
}
template<int First, int... Rest> constexpr int f() { return First + f<Rest...>(); } template<int First> constexpr int f() { return First; } int main() { f<1, 2, 3>(); return 0; }
你得到这个错误:
error C2668: 'f': ambiguous call to overloaded function while trying to resolve f<3,>() call.
这是因为可变参数包可以被赋予0个参数,所以f<3>
可以通过"扩展"到template<3, >
来与template<int First, int... Rest>
一起工作。但是,您也有template<int First>
的特殊化,所以编译器不知道该选择哪一个。
明确声明第一个和第二个模板参数是解决这个问题的一个完全有效且良好的方法。
当您尝试将基本情况更改为:
template <>
constexpr int f()
{
return 0;
}
您有一个问题,因为函数不能以这种方式专门化。类和结构可以是,但不能是函数。
解决方案1:constexpr
的C++17倍表达
template <typename... Is>
constexpr int sum(Is... values) {
return (0 + ... + values);
}
解决方案2:使用constexpr
函数
constexpr int sum() {
return 0;
}
template <typename I, typename... Is>
constexpr int sum(I first, Is... rest) {
return first + sum(rest...);
}
解决方案#3:使用模板元编程
template <int... Is>
struct sum;
template <>
struct sum<>
: std::integral_constant<int, 0>
{};
template <int First, int... Rest>
struct sum<First, Rest...>
: std::integral_constant<int,
First + sum_impl<Rest...>::value>
{};
我发现将代码从模板参数移动到函数参数通常更容易:
constexpr int sum() { return 0; }
template <class T, class... Ts>
constexpr int sum(T value, Ts... rest) {
return value + sum(rest...);
}
如果你真的想把它们作为模板参数,你可以让你的f
通过向下移动它们来调用sum
:
template <int... Is>
constexpr int f() {
return sum(Is...);
}
它是constexpr
,所以只使用int
s就可以了。
只需按照通常的方式进行总结即可。
template<int... Args>
constexpr int f() {
int sum = 0;
for(int i : { Args... }) sum += i;
return sum;
}
使用std::initializer_list
的更通用的解决方案是:
template <typename... V>
auto sum_all(V... v)
{
using rettype = typename std::common_type_t<V...>;
rettype result{};
(void)std::initializer_list<int>{(result += v, 0)...};
return result;
}
这与@T.C上面建议的内容非常相似:
#include<iostream>
#include<numeric>
template<int First, int... Rest>
constexpr int f()
{
auto types = {Rest...};
return std::accumulate(std::begin(types), std::end(types),0);
}
int main()
{
std::cout <<f<1, 2, 3>();
return 0;
}
- 递归函数计算序列中的平方和(并输出过程)
- 如何在Elixir中调用递归函数并行
- 递归函数有效,但无法记忆
- 为什么我的递归函数按降序打印,然后按升序打印?
- 为什么递归函数的最终输出是 5?
- 有没有办法使用递归函数找到数组中最小值的 INDEX?C++
- 如何将记忆应用于此递归函数?
- 如何从递归函数中完全返回,该函数给出了每个函数结果的累积相加?
- 如何编写一个递归函数,以随机的方式混淆从0到6的数字
- 编写一个函数,用递归函数检查数字是否是正方形
- 以迭代方式编写递归函数
- 我用 c++ 编写的递归函数不起作用
- 编写一个递归函数来乘以2个整数
- 如何编写递归函数来计算图形数据结构中的最短路径
- 我正试图用c++编写一个递归函数,但它一直导致堆栈溢出
- 基例如何影响使用递归函数的哪些行
- 如何编写可变模板递归函数
- 编写一个递归C++函数,计算并返回数组中整数的乘积
- 如何为递归函数编写方法定义
- 如何编写递归函数的方法定义