Topic: packaged_task<R1(Args1...)> -> packaged_task<R2(Args2)>


Author: "Mutz, Marc" <marc@kdab.com>
Date: Fri, 27 Apr 2018 13:39:14 +0200
Raw View
Hi,

Currently, when you construct a std::packaged_task from another one with
compatible signature, you get two independent shared states (ie. two
futures), because the wrapping task contains the wrapped task as if it
was any other callable.

The ship has sailed for implicit conversions, but as I myself have found
and these SO questions suggest:

https://stackoverflow.com/questions/31072279/implementing-a-simple-generic-thread-pool-in-c11

https://stackoverflow.com/questions/28179817/how-can-i-store-generic-packaged-tasks-in-a-container

There is a hole in the standard library, since while you can always
construct a std::function with a compatible signature in the first
place, this does not work for packaged_task, since the return type of
the signature determines the type of future returned from get_future().

What these SO users need, and I needed, too, recently, was a
std::packaged_task<void()> for type erasure constructed from a
packaged_task<R()>, on which get_future() was called. Alternatively,
they could use a unique_function, which, however, is also lacking in the
standard.

Now, instead of cluttering the API of packaged_task, I imagine that a
simple cast function could do the job:

    fun: some callable compatible with R()
    m_tasks: a container of packaged_task<void()>

    auto task = std::packaged_task<R()>{fun};
    auto result = task.get_future();
    m_tasks.push_back(packaged_task_cast<void()>(std::move(task)));

I deliberately didn't look into how to implement this, yet, as I wanted
to retain the API user's view for now.

Alternatively, the future and the packaged_task objects could be created
together, with a make_ function. This could also supply the much-missed
feature of binding arguments to the invocation, much like
make_shared/unique allow to pass arguments to the ctor while the
shared_ptr/unique_ptr ctors only take pointers:

   auto r = std::make_packaged_task_and_future<void()>(fun, args...);
   m_tasks.push_back(std::move(r.task)); // a packaged_task<void()>,
since this is what we asked for
   return std::move(r.future); // a future<R>, deduced from the return
type of 'fun'

Opinions?

Thanks,
Marc

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/75436f980d0846cbf4a7c949e46320a0%40kdab.com.

.


Author: Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
Date: Fri, 27 Apr 2018 16:12:43 -0700 (PDT)
Raw View
------=_Part_11566_595025575.1524870763537
Content-Type: multipart/alternative;
 boundary="----=_Part_11567_1037226738.1524870763537"

------=_Part_11567_1037226738.1524870763537
Content-Type: text/plain; charset="UTF-8"

On Friday, April 27, 2018 at 4:39:19 AM UTC-7, Mutz, Marc wrote:
>
> Hi,
>
> Currently, when you construct a std::packaged_task from another one with
> compatible signature, you get two independent shared states (ie. two
> futures), because the wrapping task contains the wrapped task as if it
> was any other callable.
>
> The ship has sailed for implicit conversions [...]

What these SO users need, and I needed, too, recently, was a
> std::packaged_task<void()> for type erasure constructed from a
> packaged_task<R()>, on which get_future() was called.


This topic has been discussed in here before:
https://groups.google.com/a/isocpp.org/d/msg/std-proposals/doVBK_QOsyY/Kabz4CVbBwAJ

Personally, I think that it would be safe to recall the ship on implicit
conversions and just make

    packaged_task<T()> pt1 = ...;
    packaged_task<void()> pt2 = std::move(pt1);

do the right thing. Yes it would be a quietly breaking change (as discussed
in the prior thread linked above), but it would break only stupid code,
AFAICT. I would be interested to see any non-stupid examples of code that
would break.


On a different topic:
I agree that the correct API for promise/future factories is to return a
`pair<promise, future>`, or in this case a `pair<packaged_task, future>`.
That seems orthogonal to the rest of your proposal, though, and is super
easy to implement with a "user-land" helper function.


On a different topic:

>    auto r = std::make_packaged_task_and_future<void()>(fun, args...);
>

This style of passing "args to bind" to a task/thread went out of style in
C++11 with the introduction of lambdas. If you want to "bind" some args to
`fun`, then you should write

    auto r = std::make_packaged_task_and_future<void()>(
        [fun, args...]() { fun(args...); }
    );

which allows you to control the capture-mode of `fun` and `args...`
completely, with no need to fiddle around with `std::reference_wrapper` and
no need to worry about thinkos leading to potentially dangling references.

HTH,
Arthur

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/04a2b72a-b666-42ed-92d0-09aa41137532%40isocpp.org.

------=_Part_11567_1037226738.1524870763537
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">On Friday, April 27, 2018 at 4:39:19 AM UTC-7, Mutz, Marc =
wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8=
ex;border-left: 1px #ccc solid;padding-left: 1ex;">Hi,
<br>
<br>Currently, when you construct a std::packaged_task from another one wit=
h=20
<br>compatible signature, you get two independent shared states (ie. two=20
<br>futures), because the wrapping task contains the wrapped task as if it=
=20
<br>was any other callable.
<br>
<br>The ship has sailed for implicit conversions [...]</blockquote><blockqu=
ote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left=
: 1px #ccc solid;padding-left: 1ex;">What these SO users need, and I needed=
, too, recently, was a=20
<br>std::packaged_task&lt;void()&gt; for type erasure constructed from a=20
<br>packaged_task&lt;R()&gt;, on which get_future() was called.</blockquote=
><div><br></div><div>This topic has been discussed in here before:</div><di=
v><a href=3D"https://groups.google.com/a/isocpp.org/d/msg/std-proposals/doV=
BK_QOsyY/Kabz4CVbBwAJ">https://groups.google.com/a/isocpp.org/d/msg/std-pro=
posals/doVBK_QOsyY/Kabz4CVbBwAJ</a><br></div><div><br></div><div>Personally=
, I think that it would be safe to recall the ship on implicit conversions =
and just make</div><div><br></div><div>=C2=A0 =C2=A0 packaged_task&lt;T()&g=
t; pt1 =3D ...;</div><div>=C2=A0 =C2=A0 packaged_task&lt;void()&gt; pt2 =3D=
 std::move(pt1);</div><div><br></div><div>do the right thing. Yes it would =
be a quietly breaking change (as discussed in the prior thread linked above=
), but it would break only stupid code, AFAICT. I would be interested to se=
e any non-stupid examples of code that would break.</div><div><br></div><di=
v><div><br></div><div>On a different topic:</div><div>I agree that the corr=
ect API for promise/future factories is to return a `pair&lt;promise, futur=
e&gt;`, or in this case a `pair&lt;packaged_task, future&gt;`. That seems o=
rthogonal to the rest of your proposal, though, and is super easy to implem=
ent with a &quot;user-land&quot; helper function.</div></div><div><br></div=
><div><br></div><div>On a different topic:</div><blockquote class=3D"gmail_=
quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pa=
dding-left: 1ex;">=C2=A0 =C2=A0auto r =3D std::make_packaged_task_and_<wbr>=
future&lt;void()&gt;(fun, args...);
<br></blockquote><div><br></div><div>This style of passing &quot;args to bi=
nd&quot; to a task/thread went out of style in C++11 with the introduction =
of lambdas. If you want to &quot;bind&quot; some args to `fun`, then you sh=
ould write<br></div><div><br></div><div>=C2=A0 =C2=A0 auto r =3D std::make_=
packaged_task_and_future&lt;void()&gt;(</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 [fun, args...]() { fun(args...); }</div><div>=C2=A0 =C2=A0 );</div><div=
><br></div><div>which allows you to control the capture-mode of `fun` and `=
args...` completely, with no need to fiddle around with `std::reference_wra=
pper` and no need to worry about thinkos leading to potentially dangling re=
ferences.</div><div><br></div><div>HTH,</div><div>Arthur</div></div>

<p></p>

-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/04a2b72a-b666-42ed-92d0-09aa41137532%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/04a2b72a-b666-42ed-92d0-09aa41137532=
%40isocpp.org</a>.<br />

------=_Part_11567_1037226738.1524870763537--

------=_Part_11566_595025575.1524870763537--

.