1

我写了以下 sumhelper:

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... );
}

这是CPP文件

#include <iostream>
#include <type_traits>
#include "Sum.hpp" 

struct A {
    int x;

    A(const int a) : x(a) { std::cout<<x<<std::endl; };

    A &operator+(const A &tmp) const {
        std::cout<<" + "<<tmp.x<<") ";
    };
};

int main () {
    std::cout<<"sum of 1,2,3,4 is : ";

    auto ans = sum(1,2.2,3,4);

    A a(1);
    A b(2);
    A c(3);

    std::cout<<a.x;
    a+b+c;

    sum(a,b,c); //Here is syntax error

    std::cout<<ans<<std::endl;
    return 0;
}

为什么我不能做 sum(a,b,c) ?当我让 a+b+c 像演示一样工作时。

当我传递对象时它会给出一个编译错误,但当我传递原始类型时它不会

我无法理解错误模板参数扣除/替换失败..如何?

4

3 回答 3

2

apply_binop这是将任意操作作为第一个参数的 variardic 的变体,以及sum将二进制传递add给它的包装器。 我相信apply_binop更好(更清楚)知道:foldr

#include <utility>
#include <iostream>

#define RETURNS(x) ->decltype(x) { return (x); }

struct add {
  template<typename T, typename U>
  auto operator()( T&& t, U&& u ) const
    RETURNS( std::forward<T>(t)+std::forward<U>(u) )
};


template<typename Op, typename T0>
auto apply_binop( Op&& op, T0&& t0 )
  RETURNS(std::forward<T0>(t0))

template<typename Op, typename T0, typename T1, typename... Ts>
auto apply_binop( Op&& op, T0&& t0, T1&& t1, Ts&&... ts )
  RETURNS(
    op(
      std::forward<T0>(t0),
      apply_binop(op, std::forward<T1>(t1), std::forward<Ts>(ts)...)
    )
  )

template<typename... Ts>
auto sum( Ts&&... ts )
  RETURNS( apply_binop( add(), std::forward<Ts>(ts)... ) )

int main() {
  std::cout << sum(1,2,3,4,5) << "\n";
  std::cout << sum(1) << "\n";
  std::cout << sum(1,2) << "\n";
  std::cout << sum(1,2,3) << "\n";
  std::cout << sum(1,2,3,4) << "\n";
  std::cout << sum(1,2,3,4.7723) << "\n";
}

这是foldr因为它将二元运算应用于最右边的两个,然后取该结果并将其与第三个最后一个应用,等等。 foldl从左边开始做同样的事情。

该宏RETURNS弥补了 C++ 无法推断单行函数的返回类型(我相信这将在 C++17 中修复)。让 gcc 4.7.2 接受上述只有两个apply_binop覆盖需要一些调整。

在没有 3 个或更多覆盖的情况下实现foldl有点棘手。

这是另一个答案,他们在其中讨论了解决此问题的更好方法:

如何使用可变参数模板实现折叠

于 2013-05-11T17:10:55.063 回答
2

这是我的错误(来自上一个答案)您应该在顶部为单个元素添加一个模板专业化。否则sum(1,2,3)将找不到匹配项,因为前两个 args 将由可变参数匹配,而另一个需要两个 args。只剩下一个了。

template <typename T>
T sum(const T& v) {
    return v;
}

另一个问题是您的 operator+ 流出而没有返回任何东西。这是未定义的行为。如果你将它定义为一个成员,它应该是 const。

struct A {
    int x;
    A(const int a) : x(a) { std::cout<<x<<std::endl; };
    A operator+(const A &a1) const
    {
        return A(a1.x + x);
    }
};

所以你的完整程序现在应该是这样的

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... );
}

struct A {
    int x;
    A(const int a) : x(a) { };
    A operator+(const A &a1) const { return A(a1.x + x); }
};

int main () {
    std::cout<<"sum of 1,2.2,3,4 is : ";
    auto ans = sum(1,2.2,3,4);
    cout << ans;


    A a(1); A b(2); A c(3);
    a+b+c;
    auto ans2 = sum(a,b,c);
    std::cout<<std::endl<<"sum of A(1),A(2),A(3) is : ";
    std::cout<<ans2.x<<std::endl;
    return 0;
}

标准输出

sum of 1,2.2,3,4 is : 10.2
sum of A(1),A(2),A(3) is : 6
于 2013-05-11T12:30:28.720 回答
1

这是一个正确的可变参数和

#include <iostream>

namespace cs540 {
    template <typename T>
    const T & sum(const T & v) {
        return v;
    }

    template <typename T, typename T2, typename ... Ts>
    T sum(const T & v, const T2 & w, const Ts & ... params) {
        return sum(w+v,params...);
    }
}

int main() {
    using namespace cs540;
    using namespace std;
    cout << sum(1.1,2,3,4,6,8,9,1.1) << endl;
}

您还需要将方法 operator+ 标记为 const

于 2013-05-11T03:25:38.470 回答