OK, I''m gonna strap on a flame-retardant suit here. That was an excellent question, and it took me about half an hour to figure it out. The reason I''m wary is that the solution is not at all fun, and I''m afraid I''ll frighten people away from STL forever. Regardless, here it is:
#include <vector>#include <iostream>#include <algorithm>#include <functional>using namespace std;class Creature;class App{public: bool DrawCreature(Creature* p);};bool App::DrawCreature (Creature *p){ cout << "drew creature: 0x" << p << endl; return true;}int main (){ App a; vector<Creature*> badGuys; badGuys.push_back ((Creature *) 1); badGuys.push_back ((Creature *) 2); badGuys.push_back ((Creature *) 3); for_each (badGuys.begin (), badGuys.end (), bind1st (mem_fun1(&App::DrawCreature), &a)); return 0;}
|
OK, that''s the answer, now let''s figure out why.
The root of the problem is that for_each calls its third parameter on each element contained (type Creature* here). The third parameter must be a free function operator () that takes a Creature * argument. The problem is that it''s not allowed to be a member function.
The solution is to create a functor class that constructs itself correctly with "a" (the app object) and calls a->DrawCreature in its operator (). You can do that by hand, or you can use the STL bindings as I''ve done.
The reason mem_fun is the wrong thing to do is that mem_fun calls a member function of Creature*, not a member function of some other class. If Creature had a function Creature::Draw (), then the for_each call you have listed would do exactly what you wanted: for each Creature *x in your vector, x->Draw () gets called. This is what mem_fun does.
Well, that''s obviously not what you want. What''s closer to you want is mem_fun1, which constructs a function mem_fun1_t which is this bad boy:
template<class R, class T, class A> struct mem_fun1_t : public binary_function<T *, A, R> { explicit mem_fun1_t(R (T::*pm)(A)); R operator()(T *p, A arg); };
|
R is the return type (bool in your case).
T is the class whose member functionw we want to call: App.
A is the argument type, Creature* here.
This almost gets us what we want. We now have an operator () that takes an App* and a Creature*, and will do the function we want on each of those. But wait, for_each requires that operator () takes one parameter, not two. D''oh!!
So, we have the lovely bind1st, that creates another functor template from this template by binding the first argument to some value we set. Hence, the functor that will call a.DrawCreature on a Creature* we pass to it is:
bind1st (mem_fun1(&App::DrawCreature), &a)
By the way, as ugly as this looks, here''s the disassembly (MSVC++ 6.0 SP3):
; 29 : ; 30 : for_each (badGuys.begin (), badGuys.end (), ; 31 : bind1st (mem_fun1 (&App::DrawCreature), &a)); mov edi, DWORD PTR _badGuys$[ebp+8] mov esi, DWORD PTR _badGuys$[ebp+4]$L13093: cmp esi, edi je SHORT $L13051 push DWORD PTR [esi] lea ecx, DWORD PTR _a$[ebp] call ?DrawCreature@App@@QAE_NPAVCreature@@@Z ; App::DrawCreature add esi, 4 jmp SHORT $L13093$L13051: