Подтвердить что ты не робот

Использование std:: accumulate

Я всегда стараюсь включать алгоритмы STL, где только могу, а не писать ручные циклы. Однако мне трудно понять, как std::accumulate вообще полезен. Всякий раз, когда мне нужно вычислять суммы или средние значения, я почти всегда прибегаю к ручным циклам, потому что мне трудно получить std::accumulate, чтобы делать то, что мне нужно.

Проблема в том, что я редко когда-либо имел простой вектор целых чисел, которые нужно суммировать. Обычно я хочу суммировать массив объектов с использованием определенной переменной-члена. Да, я знаю, что есть версия std::accumulate, которая принимает двоичную функцию, но проблема, которую я вижу, заключается в том, что этой функции нужно взять два значения типа T, где T - тип суммы, а не тип операндов. У меня возникли проблемы с пониманием того, как это полезно.

Рассмотрим случай, который, как я предполагаю, довольно распространен. У меня есть следующий класс:

struct Foo
{
    Foo(int cost_, int id_) : cost(cost_), id(id_)
    { }

    int cost;
    int id;
};

Теперь, скажем, я хочу вычислить сумму массива объектов Foo, используя Foo::cost.

Я хочу сказать:

std::vector<Foo> vec;
// fill vector with values
int total_cost = std::accumulate(vec.begin(), vec.end(), 0, sum_cost);

И sum_cost определяется как:

int sum_cost(const Foo& f1, const Foo& f2)
{
    return f1.cost + f2.cost;
}

Проблема в том, что это не работает, потому что std::accumulate ожидает BinaryFunction, которая принимает в двух экземплярах результирующего типа суммы, что в данном случае просто int. Но как это полезно для меня? Если моя BinaryFunction принимает два int s, я не могу указать, что я хочу суммировать поле cost.

Итак, почему std::accumulate разработан таким образом? Я просто не вижу здесь ничего очевидного?

4b9b3361

Ответ 1

Вы ошибаетесь в том, что оператор аккумулирования принимает два одинаковых типа. Он делает это только в том случае, если вы этого хотите. Использование оператора в частности sum = op(sum, *iter). Таким образом, ваш код:

int count = std::accumulate(stuff.begin(), stuff.end(), 0, [](int current_sum, stuff_value_t const& value) { return current_sum + value.member; });

Если вы не можете использовать lambda, тогда, конечно, вы используете стандартные вложения или boost:: bind.

Ответ 2

использовать функтор:

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

обратите внимание, что вы можете делать и другие вещи:

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