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 |