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.
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.