| Prev | Index | Next |
This lesson demonstrates how callback functions are themselves objects and can even be passed to other callback functions.
1: #include "async.h"
2:
3: void
4: hello()
5: {
6: warn << "Hello, World!\n";
7: exit(0);
8: }
9:
10:
11: void
12: docallback(callback<void>::ref cb)
13: {
14: warn << "docallback\n";
15: cb();
16:
17: // just for fun; we could have done:
18: //
19: // delaycb(1, 0, cb);
20: }
21:
22: int
23: main(int argc, char *argv[])
24: {
25: async_init();
26:
27: callback<void>::ref foo = wrap(hello);
28: delaycb(1, 0, wrap(docallback, foo));
29: amain();
30: }
Line 27 and 28 could be combined in the more straightforward call:
27: delaycb(1, 0, wrap(docallback, wrap(hello)));but we wrote it the way we did to better explain what is going on.
The interesting bit is on line 27. The result of the call to
wrap(hello) is of type
callback<void>::ref. The < and
> means we're dealing with C++ templates. Don't get
nervous. The void between the < and
> brackets is to indicate that the callback function
(hello in this case) returns void. (The
::ref thingy refers to the the ref member of
the callback class. Forget it.) Delaycb
only accepts callbacks of type callback<void>::ref.
But we'll see examples of more complicated callback
objects later.
Line 28 is a delaycb that passes the
hello callback function---i.e., foo---as a
parameter to docallback. When docallback
gets called, it invokes the callback function cb. Notice
that cb() looks just like a regular function call.
In the previous lesson you learned how to pass parameters to
callback functions; you simply supply the parameters to the callback
function as parameters to wrap. But you can get away
with doing less.
You can let wrap pass a part---or even none---of the
parameters to the callback function, and then supply the missing
parameters later. The term for the technique demonstrated in the
example below is "currying".
1: #include "async.h"
2:
3: void
4: call_0(callback<void>::ref cb)
5: {
6: cb();
7: }
8:
9: void
10: call_1(callback<void, int>::ref cb)
11: {
12: cb(1);
13: }
14:
15: void
16: call_2(callback<void, int, int>::ref cb)
17: {
18: cb(11, 22);
19: }
20:
21: void
22: fn(int x, int y)
23: {
24: warn << "fn x " << x << " y " << y << "\n";
25: }
26:
27: int
28: main()
29: {
30: call_0(wrap(fn, 111, 222));
31: call_1(wrap(fn, 99));
32: call_2(wrap(fn));
33: }
34:
Function fn returns void and expects two
int parameters. The wrap on line 30 passes
these two required parameters. Now look at call_0,
especially the type of parameter cb. Recall that
callback<void>::ref cb means that cb
is a callback function of type void that expects no
additional parameters. That makes sense, since we already supplied
the required parameters on line 30.
The wrap on line 31 passes only one parameter to
fn. Now look at the parameter of type
call_1. callback<void, int>::ref cb
means that cb is a callback function that returns
void that still expects one more (int)
parameter. The first parameter was given on line 31 already, and the
second is passed on line 12. Notice that x is 99, and
y is 1---not the other way around.
Things are very similar with the wrap on line 32 and
the type of cb on line 16. We pass no parameters, so we
still have to supply two parameters on line 18.
In essence, wrap allows you to be "lazy" about passing
parameters. The callback type expresses the return type
of the callback (first parameter between < and
>) and the types of all parameters that have yet to be
passed to the callback function (all other template parameters).
| Prev | Index | Next |