[resend, with cc this time -- my last try got lost, and the usual
channels for tracking down lost articles aren't working]
This may be considerably more clear once I fix the obvious errors. I
misread the signature of packaged_task.
On 11/04/2012 07:16 PM, Daniel Kr=FCgler wrote:
>
>
> Am 04.11.2012 20:42, schrieb Andy Lutomirski:
>>
>> packaged_task is almost perfect for use in custom thread pools, like
>> this:
>>
>> packaged_task<int> task([] { /* something */ });
>
> This example cannot work, because packaged_task can only be
> instantiated with a function type, but 'int' isn't such a beast.
This should be:
packaged_task<int ()> task([] { /* something */ });
future<int> result = task.get_future();
threadpool.submit(task);
// later on
int x = result.get();
>>
>> This doesn't work well, though: the threadpool.submit() function would
>> like to accept packaged_task<T> for any T -- the only packaged_task
>> functionality that depends on the return type (as opposed to the
>> parameter type) is get_future, and get_future can only be called once.
>>
>> This means that the submit function would need to be a template and use
>> some unnecessarily complicated trick to deal with different
>> packaged_task types.
>
> I'm unconvinced that what you are describing here really is a defect.
>
> It sounds as if you say that for similar reasons std::function
> shouldn't be a template that depends on a function type. The current
> design of packaged_task makes perfect sense, because a packaged_task
> represents a type that wraps any function-like object (very similar to
> std::function) and it also allows to call invoke this callable via a
> corresponding set of functions:
>
> void operator()(ArgTypes... );
> void make_ready_at_thread_exit(ArgTypes...);
>
> Obviously these depend on the remaining parts of the signature. So
> this seems to invalidate your claims above.
std::function, when called, returns the value that the wrapped object
returns, so its operator()'s return type depends on the function's
return type.
packaged_task's call operator returns void. It should be possible to
invoke it without depending on the wrapped function's return type.
>
>> Any number of fixes are possible. For example, packaged_task<void,
>> ArgTypes...>
>
> Do you mean packaged_task<void(ArgTypes...)> ?
Yes.
>
>> could have a member
>> template<typename F>
>> static pair<future<R>, packaged_task<void, ArgTypes...>>
>> create_void(F&& f);
>
template<typename F>
static pair<future<R>, packaged_task<void (ArgTypes...)>>
create_void(F&& f);
> I don't see how this would work, if either the return type or the
> argument types are missing.
Here's a full example:
#include <future>
#include <utility>
using namespace std;
// SubmitToThreadpool does not (and cannot) care about
// the return type of task.
void SubmitToThreadpool(packaged_task<void ()> &&task)
{
// In real code, this would involve threads.
task();
}
int main()
{
packaged_task<int ()> task([]{ return 1; });
auto result = task.get_future();
SubmitToThreadpool(move(task)); // Does not compile
if (result.get() != 1)
abort();
return 0;
}
It will compile and work if you change void to int in
SubmitToThreadpool. (If using gcc on linux, you'll need to compile with
-pthread or it blows up. I'm not sure if this counts as a bug.)
There should be a way to generate a paired future<int> and a
packaged_task<void ()> (or some equivalent object).
--Andy