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?
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 a lambda, then of course you use the standard binders or boost::bind.