2011-05-13 190 views
11

我正在使用deque,因此我可以为我的数据生成滚动平均值和差异。我将n和n^2作为一对存储在双端队列中,然后使用我自己的operator +()进行累加。使用pair with accumulate时出现问题

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

感谢

+0

我可以建议使用['提振:: accumulators'(HTTP ://www.boost.org/doc/libs/1_46_1/doc/html/accumulators.html)库? – 2011-05-13 16:33:23

+1

我认为*你应该尝试将该对的+运算符放入std命名空间中;看起来你可能会碰到C++命名空间解析规则。 – 2011-05-13 16:35:08

+0

我设法第一次编译这个代码:http://codepad.org/an0dUFgk。 – jkp 2011-05-13 16:36:06

回答

12

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>()); 
+0

谢谢。正是我需要的。我曾想过我可以提供自己的运营商+成对,并且它会被拿起。 – DanS 2011-05-16 09:24:01

+0

这个答案正是我需要的,谢谢。 – petric 2013-06-14 11:52:33

0

引用Oliver Seiler的评论:

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

[这是一个社区维基答案。随意编辑补充更正,样品等]

0

你可以对总和与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)) 
    )); 
}