The implementation of the await_suspend
method accepts the handle to the suspended coroutine as the parameter. This parameter can be
defined with either specific promise type coroutine_handle<PromiseType>
or type erased coroutine_handle<>
. The
former allows await_suspend
to access the promise of the coroutine; however, it ties the implementation to a particular type. In
contrast, using coroutine_handle<>
increases the reusability of the code because this parameter type supports all promise
types.
This rule raises an issue for the implementation of await_suspend
that accepts handles to a specific promise type and yet does not use
that information.
Noncompliant code example
struct Awaiter1
{
Event& event;
/* ... */
bool await_suspend(std::coroutine_handle<Promise> current) { // Noncompliant
return event.register_callback([current] {
current.resume();
});
}
};
struct Awaiter2
{
Event& event;
/* ... */
bool await_suspend(std::coroutine_handle<PromiseA> current) { // Noncompliant
return event.register_callback([current] {
current.resume();
});
}
bool await_suspend(std::coroutine_handle<PromiseB> current) { // Noncompliant
return event.register_callback([current] {
current.resume();
});
}
};
struct Awaiter3
{
Event& event;
/* ... */
template<typename PromiseType>
bool await_suspend(std::coroutine_handle<PromiseType> current) { // Noncompliant
return event.register_callback([current] {
current.resume();
});
}
};
Compliant solution
struct Awaiter // Instead of each of Awaiter1, Awaiter2, Awaiter3
{
Event& event;
/* ... */
bool await_suspend(std::coroutine_handle<> current) {
return event.register_callback([current] {
current.resume();
});
}
};
struct AwaiterUsingPromise
{
/* ... */
void await_suspend(std::coroutine_handle<Promise> current) { // Compliant
auto wokeUpTime = std::chrono::system_clock::now() + std::chrono::seconds(10);
current.promise().executor().schedule_at(wokeUpTime, current); // promise used here
}
};