$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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