[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3 Using the Callback API

The Callback API is fairly minimal, providing only two services:

This is best observed via walking through an example, based on samples/main-callback.cc.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3.1 Using the Callback API with static functions

Consider a function:

  static double
  CbOne (double a, double b)
  {
    std::cout << "invoke cbOne a=" << a << ", b=" << b << std::endl;
    return a;
  }

Consider also the following main program snippet:

  int main (int argc, char *argv[])
  {
    // return type: double
    // first arg type: double
    // second arg type: double
    Callback<double, double, double> one;
  }

This is an example of a C-style callback – one which does not include or need a this pointer. The function template Callback is essentially the declaration of the variable containing the pointer-to-function. In the example above, we explicitly showed a pointer to a function that returned an integer and took a single integer as a parameter, The Callback template function is a generic version of that – it is used to declare the type of a callback.

Note1: Readers unfamiliar with C++ templates may consult this reference.

The Callback template requires one mandatory argument (the return type of the function to be assigned to this callback) and up to five optional arguments, which each specify the type of the arguments (if your particular callback function has more than five arguments, then this can be handled by extending the callback implementation).

So in the above example, we have a declared a callback named "one" that will eventually hold a function pointer. The signature of the function that it will hold must return double and must support two double arguments. If one tries to pass a function whose signature does not match the declared callback, the compilation will fail.

Now, we need to tie together this callback instance and the actual target function (CbOne). Notice above that CbOne has the same function signature types as the callback– this is important. We can pass in any such properly-typed function to this callback. Let’s look at this more closely:

static double CbOne (double a, double b) {}
          ^           ^          ^
          |        ---|    ------|
          |        |       | 
Callback<double, double, double> one;

You can only bind a function to a callback if they have the matching signature. The first template argument is the return type, and the additional template arguments are the types of the arguments of the function signature.

Now, let’s bind our callback "one" to the function that matches its signature:

  // build callback instance which points to cbOne function
  one = MakeCallback (&CbOne);

This call to MakeCallback is, in essence, creating one of the specialized functors mentioned above. The variable declared using the Callback template function is going to be playing the part of the generic functor. The assignment one = MakeCallback (&CbOne) is the cast that converts the specialized functor known to the callee to a generic functor known to the caller.

Then, later in the program, if the callback is needed, it can be used as follows:

  NS_ASSERT (!one.IsNull ());

  // invoke cbOne function through callback instance
  double retOne;
  retOne = one (10.0, 20.0);

The check for IsNull() ensures that the callback is not null – that there is a function to call behind this callback. Then, one() executes the generic operator() which is really overloaded with a specific implementation of operator() and returns the same result as if CbOne() had been called directly.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3.2 Using the Callback API with member functions

Generally, you will not be calling static functions but instead public member functions of an object. In this case, an extra argument is needed to the MakeCallback function, to tell the system on which object the function should be invoked. Consider this example, also from main-callback.cc:

  class MyCb {
  public:
    int CbTwo (double a) {
        std::cout << "invoke cbTwo a=" << a << std::endl;
        return -5;
    }
  };

  int main ()
  {
    ...
    // return type: int
    // first arg type: double
    Callback<int, double> two;
    MyCb cb;
    // build callback instance which points to MyCb::cbTwo
    two = MakeCallback (&MyCb::CbTwo, &cb);
    ...
  }

Here, we pass an additional object pointer to the MakeCallback<> function. Recall from the background section above that Operator() will use the pointer to member syntax when it executes on an object:

      virtual int operator() (ARG arg)
      {
        (*m_p.*m_pmi)(arg);
      }

And so we needed to provide the two variables (m_p and m_pmi) when we made the specific functor. The line,

    two = MakeCallback (&MyCb::CbTwo, &cb);

does precisely that. In this case,

When two () is invoked,

  int result = two (1.0);

I will result in a call the CbTwo member function (method) on the object pointed to by &cb.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3.3 Building Null Callbacks

It is possible for callbacks to be null; hence it may be wise to check before using them. There is a special construct for a null callback, which is preferable to simply passing "0" as an argument; it is the MakeNullCallback<> construct:

  two = MakeNullCallback<int, double> ();
  NS_ASSERT (two.IsNull ());

Invoking a null callback is just like invoking a null function pointer: it will crash at runtime.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated on April 21, 2010 using texi2html 1.82.