Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pass lambda expression as member function pointer in c++

I have a framework function which expects an object and a member function pointer (callback), like this:

do_some_work(Object* optr, void (Object::*fptr)()); // will call (optr->*fptr)()

How can I pass a lambda expression to it? Want to do somethink like this:

class MyObject : public Object
{
    void mystuff()
    {
        do_some_work(this, [](){ /* this lambda I want to pass */ });
    }
};

The meaning of it all is to not clutter the interface of MyObject class with callbacks.

UPD I can improve do_some_work in no way because I don't control framework and because actually it isn't one function, there're hundreds of them. Whole framework is based on callbacks of that type. Common usage example without lambdas:

typedef void (Object::*Callback)();
class MyObject : public Object
{
    void mystuff()
    {
        do_some_work(this, (Callback)(MyClass::do_work));
    }
    void do_work()
    {
        // here the work is done
    }
};

SOLUTION Here's my solution based on Marcelo's answer:

class CallbackWrapper : public Object
{
    fptr fptr_;
public:
    CallbackWrapper(void (*fptr)()) : fptr_(fptr) { }
    void execute()
    {
        *fptr_();
    }
};

class MyObject : public Object
{
    void mystuff()
    {
        CallbackWrapper* do_work = new CallbackWrapper([]()
        {
           /* this lambda is passed */
        });
        do_some_work(do_work, (Callback)(CallbackWrapper::execute));
    }
};

Since we create the CallbackWrapper we can control it's lifetime for the cases where the callback is used asynchonously. Thanks to all.

like image 383
ivzave Avatar asked Aug 10 '12 11:08

ivzave


1 Answers

This is impossible. The construct (optr->*fptr)() requires that fptr be a pointer-to-member. If do_some_work is under your control, change it to take something that's compatible with a lambda function, such as std::function<void()> or a parameterised type. If it's a legacy framework that isn't under your control, you may be able to wrap it, if it's a function template, e.g.:

template <typename Object>
do_some_work(Object* optr, void (Object::*fptr)());

Then, you can implement a wrapper template:

template <typename F>
void do_some_work(F f) {
    struct S {
        F f;
        S(F f) : f(f) { }
        void call() { f(); delete this; }
    };
    S* lamf = new S(f);
    do_some_work(lamf, &S::call);
}

class MyObject // You probably don't need this class anymore.
{
    void mystuff()
    {
        do_some_work([](){ /* Do your thing... */ });
    }
};

Edit: If do_some_work completes asynchronously, you must allocate lamf on the heap. I've amended the above code accordingly, just to be on the safe side. Thanks to @David Rodriguez for pointing this out.

like image 123
Marcelo Cantos Avatar answered Oct 04 '22 04:10

Marcelo Cantos