What's the best way to sum the result of a member function for all elements in a container?

寵の児 提交于 2019-12-09 02:37:04

问题


Let's say I have the following object:

struct Foo
{
    int size() { return 2; }
};

What's the best way (most maintainable, readable, etc.) to get the total size of all objects in a vector<Foo>? I'll post my solution but I'm interested in better ideas.

Update:

So far we have:

  • std::accumulate and a functor
  • std::accumulate and a lambda expression
  • plain ol' for-loop

Are there any other workable solutions? Can you make something maintainable using boost::bind or std::bind1st/2nd?


回答1:


In addition to your own suggestion, if your compiler supports C++0x lambda expressions, you can use this shorter version:

std::vector<Foo> vf;

// do something to populate vf


int totalSize = std::accumulate(vf.begin(),
                                vf.end(),
                                0, 
                                [](int sum, const Foo& elem){ return sum + elem.size();});



回答2:


Use std::accumulate and a functor.

#include <functional>
#include <numeric>

struct SumSizes : public std::binary_function<int, Foo, int>
{
    int operator()(int total, const Foo& elem) const
    {
        return total + elem.size();
    }
};

std::vector<Foo> vf;

// do something to populate vf

int totalSize = std::accumulate(vf.begin(),
                                vf.end(),
                                0, 
                                SumSizes());



回答3:


I find Boost iterators elegants, although they can be a bit verbose (range-based algorithms would make this better). In this case transform iterators can do the job:

#include <boost/iterator/transform_iterator.hpp>
//...

int totalSize = std::accumulate(
    boost::make_transform_iterator(vf.begin(), std::mem_fn(&Foo::size)),
    boost::make_transform_iterator(vf.end(), std::mem_fn(&Foo::size)),0);

Edit: replaced "boost::bind(&Foo::size,_1)" by "std::mem_fn(&Foo::size)"

Edit: I just found that the Boost.Range library has been updated to introduce range algorithms! Here is a new version of the same solution:

#include <boost/range/distance.hpp> // numeric.hpp needs it (a bug?)
#include <boost/range/numeric.hpp> // accumulate
#include <boost/range/adaptor/transformed.hpp> // transformed
//...
int totalSize = boost::accumulate(
    vf | boost::adaptors::transformed(std::mem_fn(Foo::size)), 0);

Note: the performances are approximately the same (see my comment): internally, transformed uses transorm_iterator.




回答4:


using C++11 (and beyond) range-based for loop

std::vector<Foo> vFoo;
// populate vFoo with some values...
int totalSize = 0;
for (const auto& element: vFoo) {
    totalSize += element.size();
}



回答5:


Here is the down-to-earth solution:

typedef std::vector<Foo> FooVector;
FooVector vf;
int totalSize = 0;
for (FooVector::const_iterator it = vf.begin(); it != vf.end(); ++it) {
  totalSize += it->size();
}


来源:https://stackoverflow.com/questions/3204871/whats-the-best-way-to-sum-the-result-of-a-member-function-for-all-elements-in-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!