tags:

views:

153

answers:

3

I've got this for loop:

    std::vector<itemPtr>::iterator it;
    for(it=items.begin(); it!=items.end(); ++it)
    {
        investigators.addToLeaderInventory(*it);
    }

I'd like to convert it to something like this:

std::for_each(items.begin(), items.end(), investigators.addToLeaderInventory);

However, that line doesn't compile. g++ shows me this:

error: no matching function for call to
‘for_each(__gnu_cxx::__normal_iterator<std::tr1::shared_ptr<yarl::item::Item>*,
std::vector<std::tr1::shared_ptr<yarl::item::Item>,  
std::allocator<std::tr1::shared_ptr<yarl::item::Item> > > >,  
__gnu_cxx::__normal_iterator<std::tr1::shared_ptr<yarl::item::Item>*,  
std::vector<std::tr1::shared_ptr<yarl::item::Item>,   
std::allocator<std::tr1::shared_ptr<yarl::item::Item> > > >, <unresolved overloaded
function type>)’  
/usr/include/c++/4.4/bits/stl_algo.h:4194: note: candidates are: _Funct  
std::for_each(_IIter, _IIter, _Funct) [with _IIter =  
__gnu_cxx::__normal_iterator<std::tr1::shared_ptr<yarl::item::Item>*,   
std::vector<std::tr1::shared_ptr<yarl::item::Item>,   
std::allocator<std::tr1::shared_ptr<yarl::item::Item> > > >, _Funct = void 
(yarl::party::Party::*)(yarl::itemPtr)]

Hard to read, to say the least. I imagine the solution is pretty simple, but I can't figure out what g++ is complaining about. The signature of investigators.addToLeaderInventory() is this:

void ClassName::addToLeaderInventory(itemPtr item);

which should work with a for_each, shouldn't it? What should I change?

+1  A: 

C++ can't bind an object and a method together into a single callable "function". You have to do the binding explicitly, either via a object with a custom operator()...

class AddToLeaderInventory {
public:
    AddToLeaderInventory(party::Party& party) : party_(party) { }

    void operator()(item::Item& i) { party_.addToLeaderInventory(i); }

private:
    party::Party& party_;
};
...
std::for_each(items.begin(), items.end(), AddToLeaderInventory(investigators));

...or using a library such as Boost.Bind.

Marcelo Cantos
+3  A: 

for_each takes a callable entity of some kind. In order to call a member function on another object, you need to use mem_fun, which wraps the member function so that it can be called like an ordinary function, then you need to bind it to the object instance on which it should be called using bind1st:

std::for_each(items.begin(), items.end(), 
    std::bind1st(std::mem_fun(&ClassName::add), &investigators));

Another option is to use the more modern bind, which your implementation may provide in the std or std::tr1 namespace (if it doesn't, you can use the implementation from Boost):

using std::placeholders::_1;

std::for_each(items.begin(), items.end(), 
    std::bind(&ClassName::add, &investigators, _1);
James McNellis
This is what I was looking for. Thanks.
Max
+1  A: 

If you have lambdas then you could do

for_each(items.begin(), items.end(), 
         [&](const ItemPtr& it) {investigators.addToLeaderInventory(it);});
obelix