I always try to incorporate STL algorithms wherever I can, rather than writing manual loops. However, I'm having difficulty understanding how std::accumulate
is generally useful. Whenever I need to calculate sums or averages, I almost always end up resorting to manual loops, because I have difficulty getting std::accumulate
to do what I need.
The problem is that I rarely ever have a simple vector of integers that need to be summed. Usually, I want to sum an array of objects using a particular member variable. Yes, I know there is a version of std::accumulate
that takes a BinaryFunction, but the problem I see is that this function needs to take two values of type T
, where T
is the type of the sum, rather than the type of the operands. I'm having trouble understanding how this is useful.
Consider a case which I assume is pretty common. I have the following class:
struct Foo
{
Foo(int cost_, int id_) : cost(cost_), id(id_)
{ }
int cost;
int id;
};
Now, say I want to calculate the sum of an array of Foo
objects, using Foo::cost
.
I want to say:
std::vector<Foo> vec;
// fill vector with values
int total_cost = std::accumulate(vec.begin(), vec.end(), 0, sum_cost);
And sum_cost
is defined as:
int sum_cost(const Foo& f1, const Foo& f2)
{
return f1.cost + f2.cost;
}
The problem is, this doesn't work because std::accumulate
expects a BinaryFunction which takes in two instances of the resulting sum type - which in this case is just int
. But how is that useful to me? If my BinaryFunction takes in two int
s, I can't specify that I want to sum the cost
field.
So, why is std::accumulate
designed this way? Am I just not seeing something obvious here?
std::accumulate() is a built-in function in C++'s Standard Template Library. The function takes in a beginning iterator, an ending iterator, initial value, and (by default) computes the sum of the given initial value and the elements in the given range. The function can also be used for left folding.
Accumulate sentence example. They were unable to accumulate enough evidence to make a well-written claim. The couple hoped to accumulate enough money to make the down payment on a house. He was the first man to collect libraries, to accumulate coins.
As I expect, the manually unrolled loop is the fastest one, but more interesting is that std::accumulate is much slower than simple loop. This is my code, I compiled it with gcc 4.7 with -O3 flag. Visual Studio will need different rdtsc function implementation.
Complexity: O(n×k), where n is the distance from first to last , O(k) is complexity of f function.
You're wrong about accumulate operator taking two of the same type. It does that only if you want to. The use the operator is specifically sum = op(sum, *iter)
. Thus your code:
int count = std::accumulate(stuff.begin(), stuff.end(), 0, [](int current_sum, stuff_value_t const& value) { return current_sum + value.member; });
If you can't use lambda then of course you use the standard binders or boost::bind.
use functor:
class F { // sum Foos
F(int init = 0);
template<class T>
Foo operator()(const Foo &a, const T &b) const;
operator int() const;
};
int total_cost = std::accumulate(vec.begin(), vec.end(), F(0), F());
notice you can do other things as well:
class F { // sum foo values members
template<class T>
T operator()(const T &a, const Foo &b) const;
};
int total_cost = std::accumulate(vec.begin(), vec.end(), int(0), F());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With