【问题标题】:Problem using pair with accumulate使用对累积的问题
【发布时间】:2025-12-07 00:55:02
【问题描述】:

我正在使用双端队列,因此我可以为我的数据生成滚动平均值和方差。我将 n 和 n^2 作为一对存储在双端队列中,然后与我自己的 operator+() 一起使用累积。

#include <deque>
#include <numeric>
#include <utility>

template <typename T1, typename T2>
std::pair<T1,T2> operator+(const std::pair<T1,T2>& lhs, const std::pair<T1,T2>& rhs)
{
   return std::pair<T1,T2>(lhs.first + rhs.first, lhs.second + rhs.second);
}

namespace resource 
{
template <typename T>
class rollingStats
{
public:
   rollingStats(unsigned int n, const T& val):
      xs(n, std::pair<T,T>(val, val*val))
   {;}
   ~rollingStats()
   {;}

   T getMean(void) const
   {
      std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::pair<T,T>((T)0,(T)0));
      return sum.first / xs.size();
   }

   T getVar(void) const
   {
      const unsigned int n = xs.size();

      std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::pair<T, T > ((T)0,(T)0));

      return ((n * sum.second - sum.first*sum.first) / (n * n));
   }

   void addValue(const T& val)
   {
      xs.pop_front();
      xs.push_back(std::pair<T,T>(val,val*val) );
   }

   const std::deque<std::pair<T,T> >& getXs(void) const {return xs;}
private:
   std::deque<std::pair<T,T> > xs;
};
}

我在使用 g++ 4.1.2 时遇到无法解决的编译错误。

  [ CC         ]  resource/UnitTest: rollingStats_Test.o 
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_numeric.h: In function ‘_Tp std::accumulate(_InputIterator, _InputIterator, _Tp) [with _InputIterator = std::_Deque_iterator<std::pair<float, float>, const std::pair<float, float>&, const std::pair<float, float>*>, _Tp = std::pair<float, float>]’:
../rollingStats.hpp:45:   instantiated from ‘T resource::rollingStats<T>::getMean() const [with T = float]’
rollingStats_Test.cpp:98:   instantiated from here
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_numeric.h:89: error: no match for ‘operator+’ in ‘__init + __first.std::_Deque_iterator<_Tp, _Ref, _Ptr>::operator* [with _Tp = std::pair<float, float>, _Ref = const std::pair<float, float>&, _Ptr = const std::pair<float, float>*]()’
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_bvector.h:267: note: candidates are: std::_Bit_iterator std::operator+(ptrdiff_t, const std::_Bit_iterator&)
/usr/lib/gcc/i386-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_bvector.h:353: note:                 std::_Bit_const_iterator std::operator+(ptrdiff_t, const std::_Bit_const_iterator&)
make: *** [rollingStats_Test.o] Error 1

我在这里做错了什么?我是否需要添加自己的仿函数而不是单独依赖 STL?

谢谢

【问题讨论】:

  • 认为您应该尝试将对的 + 运算符放入 std 命名空间;看起来您可能会遇到 C++ 命名空间解析规则。
  • @Oliver:除了技术上不允许你这样做。
  • @jkp:您从未实例化导致问题的函数。
  • 我可以看到三个选项:使用采用二进制函数的累积形式,使用您需要编写的 add_pair 函数(可能是最简单的选项);子类 std::pair 并给它加法运算符(感觉很脏);添加一个新的结构/类,该结构/类具有一对或仅具有您需要的成员,并使用它而不是对(可能是最灵活的选项)。
  • 还有另一个选项(好吧,这只是 Oliver Seiler 的第一个选项的不同版本) - 将您的 operator + 移动到资源命名空间,并将其作为函数参数传递给 accumulate :@987654325 @

标签: c++ stl numeric


【解决方案1】:

std::pair 没有operator+,并且您没有为std::accumulate 提供调用您的operator+ 实现的方法。

我会将您在operator+ 中提供的功能包装在函子中...

template <typename T1, typename T2> struct pair_sum : public std::binary_function< std::pair<T1,T2>, std::pair<T1,T2>, std::pair<T1,T2> >
{
    std::pair<T1,T2> operator()(const std::pair<T1,T2>& lhs, const std::pair<T1,T2>& rhs)
    {
       return std::pair<T1,T2>(lhs.first + rhs.first, lhs.second + rhs.second);
    }
};

...并通过调用带有 4 个参数的 std::accumulate 版本来使用它:

std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::make_pair((T)0,(T)0), pair_sum<T,T>());

【讨论】:

  • 谢谢。正是我需要的。我原以为我可以只为配对提供自己的 operator+ 并且它会被拾取。
【解决方案2】:

引用Oliver Seiler的评论:

我可以看到三个选项:使用采用二进制函数的累积形式,使用您需要编写的 add_pair 函数(可能是最简单的选项);子类 std::pair 并给它加法运算符(感觉很脏);添加一个新的结构/类,它要么有一对,要么只有你需要的成员,然后用它代替一对(可能是最灵活的选择)。

[这是一个社区 wiki 答案。随意编辑以添加更正、示例等。]

【讨论】:

    【解决方案3】:

    你可以在boost::lambda的帮助下得到对的总和:

    #include <boost/lambda/bind.hpp>
    #include <boost/lambda/construct.hpp>
    
    template<typename T>
    void summarize()
    {
      typedef std::pair<T, T> pt_t;
      std::deque<pt_t> xs;
      using namespace boost::lambda;
    
      // fill xs with useful stuff
    
      pt_t res = std::accumulate(
        xs.begin(), xs.end(), std::make_pair(T(),T()),
        bind( constructor<pt_t>(),
          bind( std::plus<T>(), bind(&pt_t::first,_1), bind(&pt_t::first,_2) ),
          bind( std::plus<T>(), bind(&pt_t::second,_1), bind(&pt_t::second,_2) )
        ) );
    }
    

    【讨论】: