[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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] | [ ? ] |
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, 4 2009 using texi2html 1.78.