C++ Logo

std-proposals

Advanced search

Re: async coroutines vs. lambdas

From: Avi Kivity <avi_at_[hidden]>
Date: Thu, 14 May 2020 18:02:01 +0300
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.

Received on 2020-05-14 10:06:04