3

Is it possible to bind arguments to a member function call, and later bind the target object separately?

What I was trying to achieve is a helper function which receives a function with arbitrary arguments as an argument, and then executes it on all items in a collection.

void SomeType::Work(UINT a, UINT b, UINT c)
{
    //do something
}

template<typename Function, class Container>
void Execute(const Function& fn, const Container& collection)
{
    for(auto& item : collection)
    {
        auto bound = std::bind(fn, &item);
        bound();
    }
}

void Test()
{
    //eg. container = vector of SomeType
    auto fn = std::bind(&Sometype::Work, 10, 20, 30);
    Execute(fn, container);
}

This was failing with some error within functional:

error C2064: term does not evaluate to a function taking 3 arguments

Eventually pointing at:

see reference to function template instantiation 'void Execute<std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall SomeType::* )(UINT,UINT,UINT),void,SomeType,UINT,UINT,UINT>,UINT &,UINT &,UINT &>>(const Function &)' being compiled
with
[
    Function=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall SomeType::* )(UINT,UINT,UINT),void,SomeType,UINT,UINT,UINT>,UINT &,UINT &,UINT &>
]

I worked around it by just passing in a lambda that captures the desired values and executes the desired function on an object passed into it. I'm still left wondering if binding functions this way has any legs and I was just going about it wrong, or if it's just not doable.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Zepee
  • 1,640
  • 3
  • 20
  • 40

2 Answers2

4

You should leave a placeholder for the target object which will be bound at the 2nd time binding, when bind the member function Sometype::Work().

Try this:

using namespace std::placeholders;
auto fn = std::bind(&Sometype::Work, _1, 10, 20, 30);
                                     ~~

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
0

It sounds like you simply want to apply a function (with specific arguments) to a collection.

I don't see how that's different than using std::for_each with a specific function.

void Test()
{
    //eg. container = vector of SomeType
    auto fn1 = [/*whatever*/](const container_value_type& obj) { 
        Sometype::Work(10, 20, 30, obj);
    }
    auto fn2 = [/*whatever*/](const container_value_type& obj) { 
        Sometype::Work(40, 50, 60, obj);
    }
    std::for_each(container.begin(), container.end(), fn1);
    std::for_each(container.begin(), container.end(), fn2);
}
ZivS
  • 2,094
  • 2
  • 27
  • 48
  • Only difference is interface nicety. Not having to duplicate all the for_each and iterator begin.end, etc. That's why I was making the helper, as it was being used in a bunch of functions (container that just forwards all calls to held items), otherwise I would have just used for_each or range based for – Zepee Aug 08 '16 at 11:02
  • OK, so why not use your `Execute` but instead of using std::bind there, use std::for_each. I mean you bind the item to the function and immediately after you invoke it, so why not just call it and pass the item. IMHO you over-engineer it... – ZivS Aug 08 '16 at 11:05
  • Doesn't answer the question – Lightness Races in Orbit Aug 08 '16 at 11:47
  • @ZivS as I mentioned in the post, I did do it differently, by using lambda's and passing that into a function that will do the iteration. I was just curious about std::bind usage – Zepee Aug 08 '16 at 12:51