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