Проблема использования пары с накоплением

Я использую deque, поэтому могу генерировать скользящие средние и отклонения для моих данных. Я сохраняю n и n ^ 2 как пару в deque, а затем использую накопленный с моим собственным оператором +().

#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?

спасибо

Ответ 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);
    }
};

... и использовать это, вызывая версию std::accumulate, которая принимает 4 аргумента:

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

Ответ 2

Цитата Оливер Сеилер комментарий:

Я вижу три варианта: используйте форму накопления, которая принимает двоичную функцию, используя функцию add_pair, которую вам нужно написать (возможно, самый простой вариант); подкласс std:: pair и дать ему операторы добавления (чувствует себя грязным); добавьте новый struct/class, у которого есть пара или просто есть члены, которые вам нужны, и используйте это вместо пары (возможно, самый гибкий вариант).

[Это ответ сообщества 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) )
    ) );
}