3

I'm trying to implement a c++ function that gets a Lambda callback as a parameter. The thing is, the callback is initiated asynchronously from another function in the same (called) class. I therefore need to store the Lambda in a member variable so that it can be accessed by the asynchronous function that needs to initiate the callback.

I tried all the ways I could think of to declare, set and call the Lambda using a member variable, but the code always crashes either in the assignment or in the call.

Here's a stripped-out version of what I'm trying to do.

Declaring the function:

void function(const std::function<void()>callback);

Calling the function from the main code:

myClass->function([](){cout << "Callback called";});

If I execute callback from within function it works fine, but I couldn't find a way to store it in a member variable (e.g. m_callback) and invoke it from another function of the same class.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
Amiram Stark
  • 2,208
  • 22
  • 32

2 Answers2

5

This should work:

#include <functional>
#include <utility>

struct MyThing
{
    std::function<void()> f_;

    void SetCallback(std::function<void()> f) { f_ = std::move(f); }

    void Action() { f_(); }
};

Usage:

#include <iostream>

MyThing thing;

thing.SetCallback([](){ std::cout << "Boo\n"; });
thing.Action();
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • This works fine (even in the second asynchronous function) when the Lambda is defined inline as in your example. But if the Lambda is a parameter passed to the function, thing.Action() only works in the function itself. It causes EXC_BAD_ACCESS in the asynchronous function. – Amiram Stark Oct 27 '13 at 21:43
  • 2
    @AmiramStark: Your problem is almost guaranteed to be due to incomplete understanding of object lifetimes and synchronization. However, without a more representative example of what you're trying to do, it's hard to give any advice other than "write correct code" I'm afraid. – Kerrek SB Oct 27 '13 at 21:47
1

Just create a std::function variable, and call it.

#include <iostream>
#include <functional>

struct A{
    std::function<void()> cb;

    void function(const std::function<void()>callback){
        cb=callback;
    }
};

int main() {
    A a;

    a.function([](){std::cout << "Callback called";});

    a.cb();

}
BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • I tried it. I get a SIGSEGV when I call cb in the asynchronous function (main is still active of course). This happens both in Xcode and in Eclipse. – Amiram Stark Oct 27 '13 at 19:10
  • @AmiramStark and which compiler? What do you mean with asynchronous function? – BЈовић Oct 27 '13 at 19:46
  • In Xcode it's Apple LLVM 4.2. In Eclipse it's the latest built-in GCC compiler, I don't know the version. As for the asynchronous function, I explained this in my original question. I have no problem calling the Lambda from the function to which it is passed as a parameter. But I need to store it in a class member variable and call it from another function asynchronously (e.g. when the user touches a button or in a timeout callback). – Amiram Stark Oct 27 '13 at 21:08
  • @AmiramStark if the above code doesn't work, it is a problem in your compiler. if it works, then the problem is somewhere else – BЈовић Oct 27 '13 at 21:16
  • I find it hard to believe that two different compilers have the exact same problem and show the exact same error (as I said, your code works in the original function, but it fails if I try to call cb in the asynchronous function in the same class). – Amiram Stark Oct 27 '13 at 21:45
  • @AmiramStark: It works fine for me. I have Apple LLVM compiler 5.0 (the latest). I compile it with `clang++ -std=c++11 -stdlib=libc++ whatever.cpp` – user102008 Oct 30 '13 at 10:25