Sum of std::vector<Object> members C++
Asked Answered
D

4

6

I have Example Class:

class Example {
private:
  int testValue1;
  int testValue2;
  int testValue3;

public:
  Example(int pVal1, int pVal2, int pVal3);

  Example(const Example);

  const Example operator =(const Example);

  inline int getValue1() { return testValue1; }

  inline int getValue2() { return testValue2; }

  inline int getValue3() { return testValue3; }

};

In source code I have std::vector of Example Objects.

Is it possible with some std::algorithm, std::numeric functions make a sum of Value1 of all Obejcts in vector

something like this: std::accumulate(vector.begin(), vector.end(), 0, SomeFunctorOrOthers)....

Of course I can use an iterators... but if it is possible ii want to know it

Thank you very much!

Durkheim answered 17/10, 2013 at 11:32 Comment(0)
H
14

Sure:

int sum = 
std::accumulate (begin(v), end(v), 0, 
    [](int i, const Object& o){ return o.getValue1() + i; });

Note that, since Object is passed by const-ref to the lambda, you need to make getters const (that's a good practice anyway).

If you don't have C++11, you can define a functor with overloaded operator(). I'd go further and make it a template so you can easily decide which of the getters you'd like to call:

template<int (Object::* P)() const> // member function pointer parameter
struct adder {
    int operator()(int i, const Object& o) const
    {
        return (o.*P)() + i;
    }  
};

Pass it like this to algorithm: adder<&Object::getValue2>()

Haustorium answered 17/10, 2013 at 11:37 Comment(2)
what trick int i is doing here?Baize
It's the first parameter to the lambda function. The 'accumulate' algorithm uses it to pass the running sum.Haustorium
W
3
std::accumulate(vector.begin(), vector.end(), 0, [](const int& a, Example& b)
{
return a + b.getValue1();
});
Williford answered 17/10, 2013 at 11:37 Comment(1)
How to make it work where the member data type is float.Slocum
W
1
std::accumulate(v.begin(), v.end(), 0);

It's enough if you overload operator casting for int:

class Example {
  ...

  operator int()  { return testValue1; }
};

The drawback is, you may don't want this overload generally applies in your class.

Wolfgram answered 17/10, 2013 at 11:37 Comment(2)
I would not consider this a good reason to provide something as generic (and dangerous) as an implicit conversion to int.Aquacade
I myself don't like this, but it's just another approach. Since class Example is just an example, this solution maybe not really bad.Wolfgram
C
1

C++17

Use std::transform_reduce,

int sum =
    std::transform_reduce(v.begin(), v.end(), 0, std::plus<>(),
                            [](const Object& o) { return o.getValue1(); });

Demo

C++20 (and after)

Use ranges::views::transform (C++20), and ranges::fold_left (C++23)

auto values = v | std::ranges::views::transform([](const Object& o) { return o.getValue1(); });
int sum = std::ranges::fold_left(values, 0, std::plus<>{});
// int sum = std::accumulate(values.begin(), values.end(), 0); // C++20

Demo

Cowfish answered 24/5, 2024 at 6:53 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.