【发布时间】:2020-10-07 07:46:41
【问题描述】:
考虑以下定义invoker 类的代码 - 协程的最小返回类型。我们显式删除了 invoker 类的复制和移动构造函数。
#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;
}
代码无法在 latest GCC (10.1) 上编译,它应该完全支持 C++20 协程。
相反,我们得到一个错误,表明需要移动构造函数:
<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;
| ^~~~~~~
为什么会这样?
invoker对象是通过调用invoker_promise的get_return_object()构造的,除了f()的调用者外无法访问。在 C++17 保证复制省略的情况下,get_return_object() 返回的 invoker 是纯右值,因此在从 f() 返回之前不应实现。
由于无法从协程中访问返回的对象,我看不到任何需要在返回对象之前实现对象的情况。我错过了什么吗?
注意:我知道this question,但它:
- 两年前被问到,
- 讲的是TS版本的协程,
- 是关于VC++的实现,
- 未得到答复,并且
- 有主要讨论保证复制省略的 cmets。
【问题讨论】:
-
"有主要讨论保证复制省略的 cmets。" 保证省略就是您要问的。协程函数调用的返回值是一个纯右值,但是到达那个纯右值的路径是不同的。保证省略仅适用于纯右值,所以问题是从其源到协程函数调用者的路径是否纯粹使用纯右值。