cppreference.com 中的示例不使用 MSVC 进行编译



尝试从 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应该是不同的类型,但我可能误解了这种情况。

最新更新