Каков наилучший способ суммировать результат функции-члена для всех элементов в контейнере? - PullRequest
11 голосов
/ 08 июля 2010

Допустим, у меня есть следующий объект:

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

Каков наилучший способ (наиболее легко обслуживаемый, читаемый и т. Д.) Для получения общего size всех объектов в vector<Foo>? Я опубликую свое решение, но меня интересуют лучшие идеи.

Обновление:

Пока у нас есть:

  • STD :: Накопление и функтор
  • std :: накопить и лямбда-выражение
  • обычный старый цикл

Есть ли другие работоспособные решения? Можете ли вы сделать что-нибудь для обслуживания, используя boost::bind или std::bind1st/2nd?

Ответы [ 5 ]

25 голосов
/ 08 июля 2010

В дополнение к вашему собственному предложению, если ваш компилятор поддерживает лямбда-выражения C ++ 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();});
7 голосов
/ 09 июля 2010

Я считаю, что 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.

7 голосов
/ 08 июля 2010

Используйте std :: накопить и функтор.

#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());
6 голосов
/ 01 августа 2016

с использованием C ++ 11 (и выше) на основе диапазона для цикла

std::vector<Foo> vFoo;
// populate vFoo with some values...
int totalSize = 0;
for (const auto& element: vFoo) {
    totalSize += element.size();
}
4 голосов
/ 08 июля 2010

Вот практичное решение:

typedef std::vector<Foo> FooVector;
FooVector vf;
int totalSize = 0;
for (FooVector::const_iterator it = vf.begin(); it != vf.end(); ++it) {
  totalSize += it->size();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...