Coroutines的lambda参数是否会传递到promise类型的构造函数?

huangapple go评论58阅读模式
英文:

Are coroutine lambda arguments forwarded to the promise type's constructor?

问题

It appears that when you use a lambda to create a coroutine, the lambda's arguments are not automatically forwarded to the promise type constructor. This is why you're getting the error that the promise type constructor is being called with no arguments.

In contrast, when you declare the coroutine function directly (as in your first example), the arguments are correctly passed to the promise type constructor.

To resolve this issue, you can manually forward the Scheduler argument to the promise type constructor within the lambda:

int main() {
    Scheduler s;
    auto procedure = [&s](Scheduler&) -> ReturnObject { co_return; };
    auto p = procedure(s);
    return 0;
}

By capturing s by reference in the lambda [&s], you ensure that it is accessible within the lambda and can be forwarded to the promise type constructor as needed. This should eliminate the error you were encountering.

英文:

I'm writing an application where coroutines are executed by a scheduler. The scheduler includes a stack and some other functionality which is required for the coroutines to run properly; it doesn't make sense to have a coroutine which doesn't have access to the scheduler. I decided to make the scheduler a parameter of the promise type constructor so that whenever a coroutine is created, the promise registers it with the scheduler. Here's a simplification of my code:

#include <coroutine>

struct Scheduler {};

struct ReturnObject {
    
    struct promise_type;
    
};

struct ReturnObject::promise_type {
    
    promise_type(Scheduler &s) {
        // Register coroutine handle with s
    }
    
    ReturnObject get_return_object() {
        return {};
    }
    
    std::suspend_always initial_suspend() noexcept {
        return {};
    }
    
    std::suspend_always final_suspend() noexcept {
        return {};
    }
    
    void return_void() {}
    void unhandled_exception() {}
    
};

With these definitions, I can declare a coroutine and use it as follows:

ReturnObject procedure(Scheduler &) {
    co_return;
}

int main() {
    Scheduler s;
    auto p = procedure(s);
    return 0;
}

The above compiles and runs without issue. However, if I replace the function with an equivalent lambda:

int main() {
    Scheduler s;
    auto procedure = [](Scheduler &) -> ReturnObject { co_return; };
    auto p = procedure(s);
    return 0;
}

I get this error:

demo.cpp: In lambda function:
demo.cpp:36:67: error: no matching function for call to 'ReturnObject::promise_type::promise_type()'
   36 |     auto procedure = [](Scheduler &) -> ReturnObject { co_return; };
      |                                                                   ^
demo.cpp:13:5: note: candidate: 'ReturnObject::promise_type::promise_type(Scheduler&)'
   13 |     promise_type(Scheduler &s) {
      |     ^~~~~~~~~~~~
demo.cpp:13:5: note:   candidate expects 1 argument, 0 provided
demo.cpp:11:22: note: candidate: 'constexpr ReturnObject::promise_type::promise_type(const ReturnObject::promise_type&)'
   11 | struct ReturnObject::promise_type {
      |                      ^~~~~~~~~~~~
demo.cpp:11:22: note:   candidate expects 1 argument, 0 provided
demo.cpp:11:22: note: candidate: 'constexpr ReturnObject::promise_type::promise_type(ReturnObject::promise_type&&)'
demo.cpp:11:22: note:   candidate expects 1 argument, 0 provided

Why is this? The error indicates that the promise type constructor is being called with no arguments. However, I believe that the lambda's arguments should be forwarded to the promise type constructor as the function's are.

答案1

得分: 0

lambda不等效,因为它的operator()非静态成员函数。尝试使用参数列表构造promise,包括隐式对象参数;错误来自于在重载解析失败时尝试进行默认构造。

注意,将lambda转换为函数指针并不会有帮助:它只是为您创建一个默认初始化的闭包对象。在C++23中,您可以声明lambda为static以使其真正等效。

英文:

The lambda is not equivalent because its operator() is a non-static member function. An attempt is made to construct the promise from the argument list augmented with the implicit object argument; the error comes from attempting to default-construct it when that overload resolution fails.

Note that converting the lambda to a function pointer will not help: it just creates a default-initialized closure object for you. In C++23, you can declare a lambda static to make it truly equivalent.

huangapple
  • 本文由 发表于 2023年5月13日 12:25:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76241072.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定