C++ Logo

std-proposals

Advanced search

Re: async coroutines vs. lambdas

From: Marcin Jaczewski <marcinjaczewski86_at_[hidden]>
Date: Thu, 14 May 2020 17:33:16 +0200
czw., 14 maj 2020 o 17:02 Avi Kivity <avi_at_[hidden]> napisał(a):
>
>
> On 14/05/2020 17.54, Marcin Jaczewski wrote:
> > czw., 14 maj 2020 o 16:11 Avi Kivity <avi_at_[hidden]> napisał(a):
> >>
> >> On 14/05/2020 16.56, Marcin Jaczewski wrote:
> >>> czw., 14 maj 2020 o 15:43 Avi Kivity <avi_at_[hidden]> napisał(a):
> >>>> On 14/05/2020 16.30, Marcin Jaczewski via Std-Proposals wrote:
> >>>>> And code like:
> >>>>>
> >>>>> ```
> >>>>> lazy<int> get_custom_lambda() {
> >>>>> struct X
> >>>>> {
> >>>>> int i = 3;
> >>>>> lazy<int> operator()(){ co_return i; }
> >>>>> } x();
> >>>>> return x();
> >>>>> }
> >>>>>
> >>>>> ```
> >>>>>
> >>>>> This still crash, and this is same code as `get_real_lambda`.
> >>>>> How do you like fix it?
> >>>> If the coroutine is a member function, then
> >>>>
> >>>> If the member function was called on an rvalue object, the object is
> >>>> captured in the coroutine frame by value (and is not a reference in
> >>>> coroutine_trait's type parameters)
> >>>>
> >>>> If the member function was called on an lvalue object, the object is
> >>>> captured by reference (as the current standard requires).
> >>>>
> >>>>
> >>>>> and what if lambda is not movable?
> >>>> If the lambda cannot be moved or copied to the coroutine frame, then the
> >>>> program is ill formed (same as passing a non-copyable, non-movable
> >>>> argument).
> >>>>
> >>>>
> >>>>
> >>> But then corutine can see only this:
> >>>
> >>> ```
> >>> lazy<int> X::operator()() const
> >>> {
> >>> co_return this->i;
> >>> }
> >>> ```
> >>> There is no info if you have rvalue or lvalue; If we had
> >>> `X::operator()() &&` then it could work, but this will need lot more
> >>
> >> We do have X::operator()():
> >>
> >>
> >> https://godbolt.org/z/_YSsB4
> >>
> >>
> >>> changes than you propose.
> >>
> >> For a lambda, the compiler can see that it is called as an rvalue and
> >> tack on && by itself.
> >>
> >>
> > My point was that AFIK current lambda do not have `&&` and adding it
> > could be visible for user in other contexts,
> > If we can safely add new overload and change new case for corutines
> > that copy move `*this` if function is defined with `&&` then this
> > problem is fixed.
> > Other wise we should stick to current behavior and do not returns
> > corutines from local objects.
> >
> > btw in case you show:
> > ```
> > int bar;
> >
> > get_int().then([foo] (int val) -> future<> {
> >
> > int another = co_await get_int();
> >
> > bar = foo + val + another;
> >
> > });
> > ```
> > is different case, because do you not call `operator()()` there.
> >
> > if `then` look like this:
> > ```
> > task<> then(T call)
> > {
> > co_await call();
> > }
> > ```
> > Then you do not have problem with not coping lambda. because `call`
> > will be embedded in context of `then`.
>
>
> Yes, but I don't want to create a coroutine frame in then(). Most of the
> arguments to my then() are plain lambdas, not coroutines. They are
> perfectly happy with the lambda being destroyed once its operator()()
> returns. It would be a huge source of new allocations.
>
>


Then why do not use `auto val = co_await get_int();`? your code need
live till `bar = foo + val + another;` and you do allocation in this
code already.

Received on 2020-05-14 10:36:29