我正在尝试创建一个通用和功能模板。此模板为left associative
。以下是我的实施
int result=0;
template <typename D, typename T>
const T &sum_helper(const D &d, const T &v) {
result=result+v;
return result;
}
int pass(...){}
template <typename D, typename T1, typename... Ts>
auto sum_helper(const D &d, const T1 &v1, const Ts &... params) -> decltype(v1 + sum_helper(d, params...)) {
return v1 + sum_helper(d, params... );
}
class A {};
template <typename... Ns>
struct seq {};
template <typename... Ts>
auto sum(const Ts &... params) -> decltype(sum_helper(A(), params...))
{
return pass((sum_helper(seq<Ts...>(),params)) ...,1);
}
但是,当我将其称为sum(1,2,3,4)
时,它始终会输出0
。怎么了?我知道应该纠正pass
。但是纠正它的方法是什么?
答案 0 :(得分:3)
这是一个更简单的解决方案:
#include <iostream>
using namespace std;
template <typename T1>
auto _sum(T1 & _ret, const T1 & _t1) -> T1
{
_ret += _t1;
return _ret;
}
template <typename T1, typename... Ts>
auto _sum(T1 & _ret, const T1 & _t1, const Ts &... params) -> T1
{
_ret += _t1;
return _sum(_ret, params...);
}
template <typename T1, typename... Ts>
auto sum(const T1 & _t1, const Ts &... params) -> T1
{
T1 ret = _t1;
return _sum(ret, params...);
}
int main()
{
cout << sum(1, 2, 3, 4, 5) << endl;
return 0;
}
答案 1 :(得分:3)
原始答案不起作用,因为尾随返回类型在其声明点之前使用了重载。在知道其返回类型之前,也无法转发声明函数。所以我们需要一个辅助结构。这是(很可能现在非常复杂)有效的版本:
#include <utility>
template <typename...>
struct sum_impl;
/* This is the base case */
template <typename T1, typename T2>
struct sum_impl<T1, T2>
{
typedef decltype(std::declval<const T1&>() + std::declval<const T2&>()) result_type;
static result_type doit(const T1& v1, const T2& v2)
{
return v1 + v2;
}
};
/* And here is the recursive definition for left-associativity */
template <typename T1, typename T2, typename... Ts>
struct sum_impl<T1, T2, Ts...>
{
typedef decltype(std::declval<const T1&>() + std::declval<const T2&>()) step_type;
typedef typename sum_impl<step_type, Ts...>::result_type result_type;
static result_type doit(const T1& v1, const T2& v2, const Ts&... rest)
{
return sum_impl<step_type, Ts...>::doit(v1 + v2, rest...);
}
};
template <typename... Ts>
typename sum_impl<Ts...>::result_type sum(const Ts&... args)
{
return sum_impl<Ts...>::doit(args...);
}
这是一个版本,它保留了Named的答案的简单性,但仍然是关联的:
/* not really needed, unless someone wants to call sum with only a single argument */
template <typename T>
T sum(const T& v)
{
return v;
}
/* This is the base case */
template <typename T1, typename T2>
auto sum(const T1& v1, const T2& v2) -> decltype( v1 + v2 )
{
return v1 + v2;
}
/* And here is the recursive definition for left-associativity */
template <typename T1, typename T2, typename... Ts>
auto sum(const T1& v1, const T2& v2, const Ts&... rest) -> decltype( sum(v1 + v2, rest...) )
{
return sum(v1 + v2, rest... );
}
答案 2 :(得分:1)
但是当我把它称为sum(1,2,3,4)时,它总是输出0。怎么了?
这是因为pass
没有返回任何内容所以你所拥有的是未定义的行为,因为你正在流出一个非void函数而没有返回任何东西。
我不知道为什么你甚至需要pass
return pass((sum_helper(seq<Ts...>(),params)) ...,1);
您可以展开可变参数并将它们直接发送到sum_helper
。像这样
return sum_helper(seq<Ts...>(),params...);
然而,更简单的版本将是
template <typename T>
T sum(const T& v) {
return v;
}
template <typename T1, typename T2>
auto sum(const T1& v1, const T2& v2) -> decltype( v1 + v2) {
return v1 + v2;
}
template <typename T1, typename T2, typename... Ts>
auto sum(const T1& v1, const T2& v2, const Ts&... rest) -> decltype( v1 + v2 + sum(rest...) ) {
return v1 + v2 + sum(rest... );
}
int main() {
cout << sum(1,2,3,4);
}
Rollie的回答提供了一个更简单的版本。