Reputation: 35188
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:
Are there any other workable solutions? Can you make something maintainable using boost::bind
or std::bind1st/2nd
?
Upvotes: 15
Views: 6697
Reputation: 81
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();
}
Upvotes: 6
Reputation: 248159
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();});
Upvotes: 32
Reputation: 5551
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
.
Upvotes: 7
Reputation: 49842
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();
}
Upvotes: 4
Reputation: 35188
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());
Upvotes: 8