Jitesh Dani
Jitesh Dani

Reputation: 385

foreach algorithm in C++

Is there a way to have a return value from the function that I pass to foreach.

For ex: I have,

void myfunction (int i) 
{
        cout << " " << i;
}

vector<int> myvector;
myvector.push_back(10);
for_each (myvector.begin(), myvector.end(), myfunction);

Lets say, I want to count the number of elements in the vector using some rule, I want to have a return value from myFunction, is this possible?

Upvotes: 3

Views: 1624

Answers (10)

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 248199

You can adapt std::for_each to do this as GMan showed.

But a better solution is to use the correct algorithm.

You should be able to use std::count or std::count_if, or perhaps std::accumulate. These allow you to return one result for processing the entire sequence.

Alternatively std::transform allows you to return a result for each element in the sequence, creating a new output sequence containing the results.

Upvotes: 1

int3
int3

Reputation: 13201

No. But you can make myfunction a functor, pass it a pointer to some memory, and store your return value through that pointer.

struct MyFunctor {
    int *count;
    MyFunctor(int *count_) : count(count_) { }
    void operator()(int n) {
        if (n > 5) (*count)++;
    }
};

int main() {
    vector<int> vec;
    for (int i=0; i<10; i++) vec.push_back(i);
    int count = 0;
    for_each(vec.begin(), vec.end(), Myfunctor(&count));
    printf("%d\n", count);
    return 0;
}

Edit: As the comments have pointed out, my first example would've failed as for_each would have made a copy of MyFunctor, so we couldn't have retrieved the return value from our original object. I've fixed along the lines of the original approach; but you really should look at GMan's solution which is more elegant. I'm not sure about the portability, but it does work on my gcc (4.4.2). And as the others have mentioned, whenever possible, use what <algorithm> provides.

Upvotes: 5

Matthieu M.
Matthieu M.

Reputation: 300179

Okay, I fear that you chose your example badly when you picked up a counting problem...

The problem is that for_each is extremely general and more specific algorithms exist for particular implementation (count, accumulate, transform, ...)

So let's pick up another example: for_each is typically used to apply a mutating operation on the objects it treats. It does not prevent you to collect statistics while doing so.

We have to take care, though for_each does return a Predicate object, there is no guarantee that this object was used on every item in the range. The implementation is free to copy the predicate around and use copies on part of the range... so the copy you are finally returned could be off the bat.

class Predicate
{
public:
  Predicate(size_t& errors) : m_errors(errors) {}
  void operator()(MyObject& o)
  {
    try { /* complicated */ } catch(unfit&) { ++m_errors; }
  }
private:
  size_t& m_errors;
};

std::vector<MyObject> myVec;
// fill myVec

size_t errors = 0;
std::for_each(myVec.begin(), myVec.end(), Predicate(errors));

The trick here is that all copies of the original predicate will point to the same size_t variable, thus this variable has been correctly updated.

Upvotes: 1

Mads Elvheim
Mads Elvheim

Reputation:

std::for_each isn't designed for that. Use std::count to count the number of elements which is equal to some value, or std::count_if to count the elements which satisfies some predicate:

std::vector<SomeType> vec;
std::count(vec.begin(), vec.end(), SomeType(9));
/*or */
bool myfunc(const SomeType& v)
{
    return v == 9;
}
std::count_if(vec.begin(), vec.end(), f);

If you just want to copy the contents of a container to an ostream object like std::cout, use std::copy instead:

std::vector<SomeType> vec;
...
std::copy(vec.begin(), vec.end(), \
    std::ostream_iterator<SomeType>(std::cout," "));

If you need the return value from each invocation of the function, use std::transform:

std::vector<SomeType> src;
std::vector<SomeType> result;
int myfunc(int val)
{
    ...
}
std::transform(src.begin(), src.end() \
    result.begin(), myfunc);

std::transform is also overloaded so it works for binary functions as well as unary functions.

Upvotes: 1

qba
qba

Reputation: 1311

If you want powerful foreach there is BOOST_FOREACH makro. Also boost is mostly header library so you can include only boost_foreach.hpp (afair) to your project. Example:

BOOST_FOREACH( int & i , my_vector )
{
     i = 0;
}

My_vector can be vector<int> or int[] or any other kind of iterator.

Upvotes: 3

Greg Bacon
Greg Bacon

Reputation: 139681

It's doable:

int main()
{
  std::vector<int> v;
  for (int i = 1; i <= 10; i++)
    v.push_back(i);

  int hits = 0;
  CountEven evens(&hits);
  std::for_each(v.begin(), v.end(), evens);
  std::cout << "hits = " << hits << std::endl;

  return 0;
}

But look at the nasty implementation of CountEvens:

class CountEven {
  public:
  CountEven(int *hits) : hits(hits) {}
  CountEven(const CountEven &rhs) : hits(rhs.hits) {}
  void operator() (int n) { if (n % 2 == 0) ++*hits; }

  private:
  int *hits;
};

Note that the copy constructor causes multiple instances to share the same pointer.

Use std::count or std::count_if.

Upvotes: 0

Steinbitglis
Steinbitglis

Reputation: 2614

Take a look at <algorithm>.

I think std::count_if is the one you are looking for.

Upvotes: 0

GManNickG
GManNickG

Reputation: 504203

for_each will return a copy of the functor you passed it. This means you could do this:

template <typename T>
class has_value
{
    has_value(const T& pValue) : mValue(pValue), mFlag(false) {}

    void operator()(const T& pX)
    {
        if (pX == mValue)
            mFlag = true;
    }

    operator bool(void) const { return mFlag; }
private:
    T mValue;
    bool mFlag;
};

bool has_seven = std::for_each(myvector.begin(), myvector.end(), has_value<int>(7));

For example. But for counting and the like, check out algorithm and see if your function already exists. (Like count)

Upvotes: 9

UncleBens
UncleBens

Reputation: 41351

There is a special-purpose std::count (count occurrences of a value) and std::count_if (count when predicate returns true) for that. Don't abuse std::for_each for what it was not intended for.

Upvotes: 13

Martin Beckett
Martin Beckett

Reputation: 96157

Isn't this what functors are for ?

Upvotes: 2

Related Questions