I am using a deque so I can generate rolling averages and variances for my data. I store n and n^2 as a pair in the deque and then use accumulate with my own 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.p开发者_运维百科op_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;
};
}
I get a compilation error using g++ 4.1.2 which I can't resolve.
[ 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
What have I got wrong here? Do I need to add my own functor instead of relying on the STL alone?
thanks
std::pair
doesn't have an operator+
, and you haven't provided a way for std::accumulate
to call your implementation of operator+
.
I would wrap the functionality you provided in operator+
in a functor...
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);
}
};
...and use that by calling the version of std::accumulate
that takes 4 arguments:
std::pair<T,T> sum = std::accumulate(xs.begin(), xs.end(), std::make_pair((T)0,(T)0), pair_sum<T,T>());
Quoting Oliver Seiler's comment:
I can see three options: use the form of accumulate that takes a binary function, using an add_pair function you'd need to write (probably the simplest option); subclass std::pair and give it addition operators (feels dirty); add a new struct/class that either has a pair or just has the members you need, and use that instead of the pair (probably the most flexible option).
[This is a community wiki answer. Feel free to edit to add corrections, samples, etc.]
You can get sum of pairs with help of 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) )
) );
}
精彩评论