Consider the following code that defines the invoker class - a minimal return type for a coroutine. We explicitly delete the copy and move constructors of the invoker class.
#include <coroutine>
#include <cstdlib>
class invoker {
public:
class invoker_promise {
public:
invoker get_return_object() { return invoker{}; }
auto initial_suspend() { return std::suspend_never{}; }
auto final_suspend() { return std::suspend_never{}; }
void return_void() {}
void unhandled_exception() { std::abort(); }
};
using promise_type = invoker_promise;
invoker() {}
invoker(const invoker&) = delete;
invoker& operator=(const invoker&) = delete;
invoker(invoker&&) = delete;
invoker& operator=(invoker&&) = delete;
};
invoker f() {
co_return;
}
The code does not compile on latest GCC (10.1), which is supposed to have full support for C++20 coroutines.
Instead, we get an error that indicates that the move constructor is required:
<source>: In function 'invoker f()':
<source>:23:1: error: use of deleted function 'invoker::invoker(invoker&&)'
23 | }
| ^
<source>:17:5: note: declared here
17 | invoker(invoker&&) = delete;
| ^~~~~~~
Why is this so?
The invoker object is constructed by calling get_return_object() of the invoker_promise, it can't be accessed except from the caller of f(). With C++17 guaranteed copy elision, the invoker returned by get_return_object() is a prvalue, and hence should not be materialized until after it is returned from f().
Since the returned object cannot be accessed from within the coroutine, I cannot see any situation where we might need to materialize the object before returning it. Am I missing something?
Note: I'm aware of this question, but it:
- was asked two years ago,
- is about the TS version of coroutines,
- is about VC++'s implementation,
- is unanswered, and
- has comments that mainly talk about guaranteed copy elision.