Boost logo

Boost :

From: Douglas Gregor (gregod_at_[hidden])
Date: 2001-06-13 10:17:37

On Wednesday 13 June 2001 10:29, you wrote:
> williamkempf_at_[hidden] writes:
> | > So the boost::function<> or the object returned from bind need to be
> | > packaged somehow to be able to pass it through a queue.
> |
> | Bind should not do this, as it's an orthogonal concept, as pointed
> | out.
> no I want the defer_call to do that...
> | > So perhaps a "defer_call" that packages function objects with
> | > operator()() would be more suitable for Boost.Thread or boost in
> | > general?
> |
> | Boost.Function already does this (I assume you're confused about this
> | because there are no virtual methods in boost::function<>, but trust
> | us, Boost.Function is a "deferred call" model).
> I might be confused... but I really cannot see how I can pass a
> function<> through a queue. (without limiting to only one return type)
> OR... all such object need to f.ex. be repackaged into function<void>
> before being passed to the queue. (it that even allowed?)

Perhaps some examples would help. Here's some of what Boost.Function can do:

static void printNum(int i) { cout << i << endl; }

struct PrintAndNegate {
        int operator()(long i) const { cout << -i << endl; return -i; }

boost::function<void, int> f;
f = printNum;
// ...
f(5); // prints 5 because "f" contains a pointer to printNum
// ...
f = PrintAndNegate();
// ...
f(6); // prints -6 because "f" contains a printAndNegate object
The assignments to f are done far in advance of the calls to "f", so 
boost::function is deferring calls. 
"f" is declared to take a single int parameter and return void. printNum 
exactly matches this signature, so we would expect it to work. 
PrintAndNegate, however, requires a conversion from int->long and requires 
"f" to swallow the int return value (it does both, so the above code works). 
The above code is a deferred call. Now take a step over to the realm of 
binding arguments. I'll just do something the standard library has:
void multiply_and_print(int x, int y) { cout << x*y << endl; }
// ...
vector<int> v;
// put some numbers in v...
for_each(v.begin(), v.end(), bind1st(&multiply_and_print, 42));
So this code prints each of the numbers in v multiplied by 42. The bind1st 
function takes a function object (or function pointer) and an argument (42 in 
our case) and returns a new function object that calls the function pointer 
(to multiply_and_print) with the first parameter bound to 42.
Now, we can use these two concepts together to get what you originally wanted 
from defer_call. However, note that the two concepts have no overlap. Neither 
example requires any part of the other.
So now we can use a bound multiply_and_print with boost::function
f = bind1st(&multiply_and_print, 42);
// ...
f(3); // prints 126
For your example with the queue of threads to start, you would have to decide 
on a common return type for the boost::function objects (most likely void). 
The return type of the actual functions that are being called as threads 
won't be relevant, then, because the result will be eaten by boost::function. 
This is no less powerful than your defer_call example: the return types must 
all be normalized to one type anyway because of static type checking.

Boost list run by bdawes at, gregod at, cpdaniel at, john at