tags:

views:

382

answers:

10

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?

+4  A: 

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.

int3
This shouldn't work. The functor is copied into `for_each`, and that copy is the one that counts. You should use the return value of `for_each`.
GMan
The actual alternative is to have `MyFunctor` holds a reference to an external object, this way all copies share the same reference and thus the pointed to object is updated correctly.
Matthieu M.
-1 As it is the usage is indeed wrong.
UncleBens
And -1 because `for_each` isn't the right algorithm to use in the first place.
jalf
He asked a more general question, but then gave a more specific use case. Is it that wrong to answer the more general question? The others have brought up STL algorithms more tailored to the OP's example, and I've conceded that in my answer; but if the OP didn't accept those then perhaps he was more interested in the general case.
int3
+2  A: 

Isn't this what functors are for ?

Martin Beckett
+15  A: 

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.

UncleBens
I think that in this particular case, the OP is trying to give an example ("let's say") of what he would like to accomplish, though `std::count` is useful for this case, your answer does not demonstrate how to solve the more generic question.
Matthieu M.
+7  A: 

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)

GMan
I was half way through the same code when your answer popped up, glad to see I wasn't the only one who went right to this.
tzenes
+1 for the nice cast trick, I guess I still have a lot to learn about functors
int3
This isn't portable though, there's no guarantee that `for_each` won't copy the input function for the return value before applying the passed copy to the input range, or that it won't make multiple copies and apply different copies to each member of the range.
Charles Bailey
The standard says "Applies f to the result of dereferencing every iterator in the range [first, last), startingfrom first and proceeding to last - 1. Returns: f." The SGI website also says, "For_each returns the function object after it has been applied to each element." I think any implementation that returns a pre-apply copy would be non-standard conforming, right? The entire purpose of return value is to get the applied functor.
GMan
This just does not work. Because the implementation is free to copy your predicate around, you may well end up with a copy that has never seen a single `7` during its lifetime...
Matthieu M.
The standard says nothing about being free-to-copy, and only says the `f` itself shall be applied to the elements, and `f` shall be returned. Any `for_each` implementation that doesn't do this would be much less useful, and according to my understanding non-conforming.
GMan
A: 

Take a look at <algorithm>.

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

Styggentorsken
A: 

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.

Mads Elvheim
A: 

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.

Greg Bacon
+3  A: 

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.

qba
Nice alternative, though I don't like macro it's just so convenient there.
Matthieu M.
+1  A: 

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.

Matthieu M.
A: 

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.

jalf