我正在编写一个应用程序,其中协程由调度程序执行。调度程序包括堆栈和协程正常运行所需的一些其他功能;拥有无法访问调度程序的协程是没有意义的。我决定将调度程序作为 Promise 类型构造函数的参数,以便每当创建协程时,Promise 都会将其注册到调度程序。这是我的代码的简化:
#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() {}
};
有了这些定义,我可以声明一个协程并按如下方式使用它:
ReturnObject procedure(Scheduler &) {
co_return;
}
int main() {
Scheduler s;
auto p = procedure(s);
return 0;
}
以上编译并运行没有问题。但是,如果我用等效的 lambda 替换该函数:
int main() {
Scheduler s;
auto procedure = [](Scheduler &) -> ReturnObject { co_return; };
auto p = procedure(s);
return 0;
}
我收到此错误:
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
这是为什么呢?该错误表明正在调用不带参数的 Promise 类型构造函数。但是,我认为 lambda 的参数应该像函数一样转发到 Promise 类型构造函数。
lambda 不等价,因为它的
operator()
是一个 非静态 成员函数。 尝试从用隐式对象参数扩充的参数列表构造承诺;该错误来自于在重载解析失败时尝试默认构造它。
请注意,将 lambda 转换为函数指针不会有帮助:它只是为您创建一个默认初始化的闭包对象。 在 C++23 中,您可以声明 lambda
static
以使其真正等效。
在 C++20 中,您还可以重载
promise_type
的构造函数作为解决方法:
struct ReturnObject::promise_type {
promise_type(Scheduler &s) {
// Register coroutine handle with s
}
// workaround for non-static lambdas (ignore implicit this argument)
promise_type([[maybe_unused]] auto &IgnoreMe, Scheduler &s) : promise_type(s) {
}
// ...
};