tags:

views:

281

answers:

4

According to the first answer to this question, the functor below should be able to retain a value after being passed to foreach ( I couldn't get the struct Accumulator in the example to compile, so built a class).

class Accumulator
{
    public:
        Accumulator(): counter(0){}
        int counter;
        void operator()(const Card & c) { counter += i; }
};

Example usage ( as per the example )

// Using a functor
Accumulator acc;
std::for_each(_cards.begin(), _cards.end(), acc);
// according to the example - acc.counter contains the sum of all
// elements of the deque 

std::cout << acc.counter << std::endl;

_cards is implemented as a std::deque<Card>. No matter how long _cards gets, acc.counter is zero after the for_each completes. As I step through in the debugger I can see counter incrementing, however, so is it something to do with acc being passed by value?

+2  A: 

Yes, it's definitely linked to acc being passed by value.

Modify your accumulator as follows :

class Accumulator
{
    public:
        Accumulator(): counter(new int(0)){}
        boost::shared_ptr<int> counter;
        void operator()(int i) { *counter += i; }

        int value() { return *counter; }
};
Benoît
Ew, heap allocation just to get the result?
GMan
@GMan: Yes. I'm come to the conclusion that `std::for_each` is almost an anti-pattern -- something that looks like it should be useful, but in nearly every case does something just wrong enough that using it is counterproductive.
Jerry Coffin
@Jerry: Somewhat, I agree. It's often more work that just doing it by hand. Luckily lambdas make `for_each` one of the most used algorithms, I think.
GMan
@GMan:Yes, lambdas help in a way, but in another way they actually do even more harm. Think of `for_each` as a hammer. It doesn't work well for driving screws. Using `for_each` with lambdas is often equivalent to using a big enough sledge hammer that it *can* drive screws (in a fashion). A screwdriver still works better...
Jerry Coffin
@Jerry: But lambda's are built right in! (Maybe I should specify I mean in 0x.) They're often way easier to read.
GMan
@GMan: yes, they're built right in -- but that still doesn't make `for_each` the right tool for doing accumulate's (as in this case) or copies (as is also frequently seen).
Jerry Coffin
@Jerry: Oh, I see. I was just talking about general iterate through elements with a task. Lambda's + `for_each` *could* do anything, but I agree there are simpler alternatives for specific tasks, where lamba's are not appropriate.
GMan
@GMan:Not only are there "simpler alternatives for specific tasks", but I'd go so far as to say there are superior alternatives of nearly *all* tasks.
Jerry Coffin
As an example, standard C++ is missing std::iota from STL. If you want to implement that, you can either write a loop or you can use for_each, no other algorithm is better (well, maybe fill with a really nasty functor having a mutable field). The non-`for_each` standard algorithms cover many cases, but they're not omniscient. I think the practical problem with for_each isn't that it's conceptually useless (it's not), it's just that the way C++ syntax is, for_each is barely better than the equivalent loop. It's like `/=` for integers: nobody would care if they had to write `a = a / 2` instead.
Steve Jessop
A: 

Hey refer this one. Its the same question http://stackoverflow.com/questions/2102056/foreach-doesnt-this-work-as-int

Yogesh Arora
This should probably have been a comment rather than an answer.
KingRadical
I dont get the link for putting in a comment...maybe its because i m a new member and dont have too much reputation
Yogesh Arora
+5  A: 

This was just asked here.

The reason is that (as you guessed) std::for_each copies its functor, and calls on it. However, it also returns it, so as outlined in the answer linked to above, use the return value for for_each.

That said, you just need to use std::accumulate:

int counter = std::accumulate(_cards.begin(), _cards.end(), 0);

A functor and for_each isn't correct here.


For your usage (counting some, ignoring others), you'll probably need to supply your own functor and use count_if:

// unary_function lives in <functional>
struct is_face_up : std::unary_function<const Card&, const bool>
{
    const bool operator()(const card& pC) const
    {
        return pC.isFaceUp(); // obviously I'm guessing
    }
};

int faceUp = std::count_if(_cards.begin(), _cards.end(), is_face_up());
int faceDown = 52 - faceUp;

And with C++0x lambda's for fun (just because):

int faceUp = std::count_if(_cards.begin(), _cards.end(),
                            [](const Card& pC){ return pC.isFaceUp(); });

Much nicer.

GMan
Thanks. Happy now?! :-) By the way, does my comment above regarding `faceup` and `facedown` still invalidate the need for for_each? I'm thinking `std::accumulate` is not quite what I'm after.
BeeBand
No, it's sill right. However, the count in your case will be a `std::pair<int, int>`
MSalters
+2  A: 

This is because internally the std::for_each() makes a copy of the functor (as it is poassable to pass temporary object). So internally it does do the sum on the copy not on the object you provided.

The good news is that std::for_each() returns a copy of the functor as a result so you can access it from there.

Note: There are other standard algorithms you could use. Like std::accumulate().
But suppose this is just a simplified example and you need for_each() to something slightly tricker than the example there are a couple of techniques to allow you access to the accumulator object.

#include <iostream>
#include <algorithm>
#include <vector>

class Card{ public: int i;};
class Accumulator
{
    public:
        Accumulator(): counter(0){}
        int counter;
        void operator()(const Card & c) { counter += c.i; }
};


int main()
{
    std::vector<Card>   cards;

    Accumulator a = std::for_each(cards.begin(), cards.end(), Accumulator());

    std::cout << a.counter << std::endl;

}

Alternatively you can change you Accumalator to increment a reference that is used within the current scope.

#include <iostream>
#include <algorithm>
#include <vector>

class Card{ public: int i;};
class Accumulator
{
        int&  counter;
    public:
        // Pass a reference to constructor.
        // Copy construction will pass this correctly into the internal object used by for_each
        Accumulator(int& counterRef): counter(counterRef){}
        void operator()(const Card & c) { counter += c.i; }
};


int main()
{
    std::vector<Card>   cards;

    int counter = 0;  // Count stored here.

    std::for_each(cards.begin(), cards.end(), Accumulator(counter));

    std::cout << counter << std::endl;

}
Martin York
Copying for each iteration is probably an exaggeration. It just takes the predicate by value, the only thinkable alternative being accepting it by const reference - which still wouldn't allow this usage (non-const `operator()`).
UncleBens
@UncleBens, yes, debug revealed that the default ctor gets called once (I assume on the `Accumulator acc` declaration) and then a Copy Ctor gets called twice - regardless of `_cards.size()`.
BeeBand
Missworded. Will correct.
Martin York