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

2.2 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] [ ? ]

2.2.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 snippett:

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

This class template Callback implements what is known as the Functor Design Pattern. It is used to declare the type of a callback. It contains 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 function has more than five arguments, then this can be handled by extending the callback implementation).

So in the above, we have a declared a callback named "one" that will eventually hold a function pointer. 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);

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

// this is not a null callback
  NS_ASSERT (!one.IsNull ());
  // invoke cbOne function through callback instance
  double retOne;
  retOne = one (10.0, 20.0);

The check IsNull() ensures that the callback is not null; that there is a function to call behind this callback. Then, one() returns the same result as if CbOne() had been called directly.


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

2.2.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 a (raw) pointer to the MakeCallback<> function, that says, when two () is invoked, to call the CbTwo function on the object pointed to by &cb.

A variation of this is used when objects are referred to by ns-3 smart pointers. The MakeCallback API takes a raw pointer, so we need to call PeekPointer () to obtain this raw pointer. So the example above would look like:

class MyCb : public Object {
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;
  Ptr<MyCb> cb = CreateObject<MyCb> ();
  // build callback instance which points to MyCb::cbTwo
  two = MakeCallback (&MyCb::CbTwo, PeekPointer (cb));
  ...
}

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

2.2.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> ();
  // invoking a null callback is just like
  // invoking a null function pointer:
  // it will crash at runtime.
  //int retTwoNull = two (20.0);
  NS_ASSERT (two.IsNull ());

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

This document was generated on July, 20 2008 using texi2html 1.76.