Какой лучший способ суммировать результат функции-члена для всех элементов в контейнере?
Скажем, у меня есть следующий объект:
struct Foo
{
int size() { return 2; }
};
Какой лучший способ (наиболее удобный, читаемый и т.д.) для получения всего size
всех объектов в vector<Foo>
? Я отправлю свое решение, но меня интересуют лучшие идеи.
Update:
До сих пор мы имеем:
- std:: accumulate и функтор
- std:: accumulate и выражение lambda
- plain ol 'for-loop
Существуют ли какие-либо другие работоспособные решения? Можете ли вы сделать что-то поддерживаемое с помощью boost::bind
или std::bind1st/2nd
?
Ответы
Ответ 1
В дополнение к вашему собственному предложению, если ваш компилятор поддерживает лямбда-выражения С++ 0x, вы можете использовать эту более короткую версию:
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
Используйте std:: accumulate и функтор.
#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
Я нахожу Boost iterators elegants, хотя они могут быть немного подробными (алгоритмы на основе диапазонов сделают это лучше). В этом случае преобразует итераторы может выполнить задание:
#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);
Изменить: заменить "boost::bind(&Foo::size,_1)
" на "std::mem_fn(&Foo::size)
"
Изменить: я только что обнаружил, что библиотека Boost.Range обновлена, чтобы ввести алгоритмы диапазона! Вот новая версия того же решения:
#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);
Примечание: результаты примерно одинаковы (см. мой комментарий): внутри, transformed
использует transorm_iterator
.
Ответ 4
Ниже приведено решение проблемы:
typedef std::vector<Foo> FooVector;
FooVector vf;
int totalSize = 0;
for (FooVector::const_iterator it = vf.begin(); it != vf.end(); ++it) {
totalSize += it->size();
}
Ответ 5
с использованием С++ 11 (и за его пределами), основанного на диапазоне для цикла
std::vector<Foo> vFoo;
// populate vFoo with some values...
int totalSize = 0;
for (const auto& element: vFoo) {
totalSize += element.size();
}