尝试从 cppreference.com 编译以下示例:
#include <coroutine>
struct promise;
struct coroutine : std::coroutine_handle<promise>
{
using promise_type = struct promise;
};
struct promise {
coroutine get_return_object()
{
return { coroutine::from_promise(*this) };
}
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
struct S {
int i;
coroutine f() {
std::cout << i;
co_return;
}
};
但得到编译器错误:
error C3789: this function cannot be a coroutine: 'coroutine::promise' does not declare the member 'get_return_object()'
编译器:MSVC2019,/std:c++latest
Microsoft (R) C/C++ 优化编译器版本 19.29.30137 for x86
但是GCC12编译了它,MSVC有什么问题?
编辑1
MSVC2022相同的错误
针对 x86 优化编译器版本 19.30.30709
/std:c++latest
正如网站所说:
工作进行中:此页面正在进行更新,以反映 C++20 工作草案中包含的协程技术规范部分。
此示例不能使用 MSVC2019 编译器运行。 您可以安装并试用此版本:
https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-notes
我遇到了有问题的问题并设法解决了它。
最初让我怀疑的是
struct promise;
struct coroutine : std::coroutine_handle<promise>
{
using promise_type = struct promise;
};
因为using
声明中的struct promise
本身就是有效的独立前向声明。该错误抱怨promise
没有声明其成员函数,这表明coroutine
结构中的struct promise
掩盖了我们向前声明并稍后定义为包含据称不存在的成员函数的全局struct promise
。
显然,海湾合作委员会决定确定这些类型,而MSVC没有。
我将using
语句更改为简单地
using promise_type = promise;
并得到一个新错误:
error C2061: syntax error: identifier 'promise'
这个并没有告诉我们太多,但IntelliSense进一步报告说:
E0757 function "std::coroutine_handle<_Promise>::promise [with _Promise=promise]" is not a type name
这使我意识到我的新using
声明中的promise
与句柄类型的std::coroutine_handle<T>::promise()
成员函数混淆了。我通过使用::promise
显式限定promise
来指示它来自全局命名空间来解决此问题,如下所示:
struct promise;
struct coroutine : std::coroutine_handle<promise>
{
using promise_type = ::promise;
};
这解决了这种多义性,并防止编译器将::promise
与父类的成员函数混淆。虽然这不是原始错误的根源,但我怀疑这是示例从简单using promise_type = promise;
更改为前向声明的原因,该声明修复了coroutine
内部命名冲突以换取命名空间/范围问题。对using
语句使用显式限定的::promise
可以解决这两个问题。
我不确定为什么 GCC 允许编译 cppreference 版本,因为在我看来,全局struct promise;
和coroutine
中声明的struct promise
应该是不同的类型,但我可能误解了这种情况。