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.
	Doug

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk