简体   繁体   中英

Using std::accumulate

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM