0

I slightly modified the callback example found at [1] to move the registration in to the callee itself as follows.

// To build:
//   g++ -std=c++11 callback4.cpp

#include <stdio.h>
#include <functional>

//------------------------------------------------------------------------
// Callback function.
typedef std::function<int(int)> CallbackFunction;

//------------------------------------------------------------------------
// "Caller" allows a callback to be connected.  It will call that callback.
class Caller
{
  public:
    // Clients can connect their callback with this.
    void connectCallback(CallbackFunction cb)
    {
      printf("setting the callback..\n");
      m_cb = cb;
      // This call works
      m_cb(10);
    }

    // Test the callback to make sure it works.
    void test()
    {
      printf("Caller::test() calling callback...\n");
      int i = m_cb(10);

      printf("Result (50): %d\n", i);
    }

private:
  // The callback provided by the client via connectCallback().
  CallbackFunction m_cb;
};

//------------------------------------------------------------------------
// "Callee" can provide a callback to Caller.
class Callee
{
  public:
    Callee(Caller c, int i) : m_i(i), caller(c) { }

    // The callback function that Caller will call.
    int callbackFunction(int i)
    {
      printf("  Callee::callbackFunction() inside callback\n");
      return m_i * i;
    }

    void registerCallback() {
      caller.connectCallback(
        [this](int i) { return this->callbackFunction(i); });
    }

private:
  // To prove "this" is indeed valid within callbackFunction().
  int m_i;
  Caller caller;
};

//------------------------------------------------------------------------

int main()
{
  Caller caller;
  Callee callee(caller, 5);

  callee.registerCallback();

  // Test the callback. This fails.
  caller.test();

  return 0;
}

Here I capture the Callee by this reference in the lambda expression. But the call to test() to invoke within Caller failes throwing a bad_function_call at runtime. But calling the callback at registration time works. Any idea why that is? The output is given below.

setting the callback..
Callee::callbackFunction() inside callback
Caller::test() calling callback...
terminate called after throwing an instance of 'std::bad_function_call'
what(): bad_function_call

[1] http://tedfelix.com/software/c++-callbacks.html

1
  • 1
    You are modifying a copy of a copy of caller. Commented May 10, 2016 at 3:41

1 Answer 1

3

Lets take a look at the Callee constructor:

Callee(Caller c, int i) : m_i(i), caller(c) { }

Here you pass Caller by value, meaning you copy the object.

So in the main function the variable caller is not the same as Callee::caller. The main variablecaller have not had any callback registered.

The easy solution is to use references:

class Callee
{
  public:
    Callee(Caller& c, int i) : m_i(i), caller(c) { }
    ...

  private:
    ...
    Caller& caller;
};

A better solution might be to rethink the design, and what problem you are actually trying to solve, and about the use-cases.

Sign up to request clarification or add additional context in comments.

3 Comments

I see. That worked. But can I know why you think this could be better? Any issues that you see with this approach?
@chamibuddhika Passing around references mostly work, but it's not all situation where references can be used, making the whole scheme fall apart. It all depends very much on the use-cases though, and the problem you actually try to solve with this solution.
I see. Thanks for clarifying.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.