修改boost::asio co_spawn协程返回类型后编译报错,求解决
问题分析与解决
原可运行代码
bool FileTransferBehaviour::ConnectAndTransferFile(const std::string& _sender, const std::string& _filePath, size_t _numBytes) { // use a coroutine to accept the connection and receive the file. bool result = false; asio::co_spawn(m_ioContext, [&result, &filePath, _numBytes, this]() mutable -> asio::awaitable<void> { auto maybeSock = co_await CoAwaitClientConnection(); if (maybeSock.has_value()) { result = ReceiveFile(maybeSock.value(), filePath, _numBytes); } }, asio::detached); m_ioContext.restart(); m_ioContext.run(); return result; }
修改后报错的代码
bool FileTransferBehaviour::ConnectAndTransferFile(const std::string& _sender, const std::string& _filePath, size_t _numBytes) { // use a coroutine to accept the connection and receive the file. bool result = co_await asio::co_spawn(m_ioContext, [&filePath, _numBytes, this]() mutable -> asio::awaitable<bool> { auto maybeSock = co_await CoAwaitClientConnection(); if (maybeSock.has_value()) { co_return ReceiveFile(maybeSock.value(), filePath, _numBytes); } co_return false; }, asio::detached); m_ioContext.restart(); m_ioContext.run(); return result; }
编译错误信息
Visual Studio 2022(CL版本19.37.32824)
FileTransferBehaviour.cpp(101,42): error C2228: left of '.await_ready' must have class/struct/union [MyProject,vcxproj] FileTransferBehaviour.cpp(101,17): error C2440: 'initializing': cannot convert from 'void' to 'bool' [MyProject.vcxproj]
GCC 11.4.0
FileTransferBehaviour.cpp:101:19: error: unable to find the promise type for this coroutine 101 | bool result = co_await asio::co_spawn(m_ioContext,
问题根源
asio::co_spawn搭配asio::detached返回void,无法被co_await
当co_spawn使用asio::detached作为完成令牌时,它的返回值是void,而co_await要求操作数必须是可等待对象(awaitable),void不满足这个要求,这直接导致了编译错误。外层普通函数不能使用
co_await
C++标准规定:任何包含co_await、co_return或co_yield的函数必须是协程,即返回类型必须是符合协程要求的类型(比如asio::awaitable<T>)。而你的ConnectAndTransferFile返回的是bool,属于普通函数,不能直接使用co_await。
正确修改方案
方案1:将外层函数改为协程(推荐,符合Asio协程设计)
把ConnectAndTransferFile改成返回asio::awaitable<bool>,同时用asio::use_awaitable作为co_spawn的完成令牌,这样co_spawn会返回一个可被co_await的awaitable对象:
asio::awaitable<bool> FileTransferBehaviour::ConnectAndTransferFile(const std::string& _sender, const std::string& _filePath, size_t _numBytes) { auto result = co_await asio::co_spawn(m_ioContext, [filePath = _filePath, _numBytes, this]() mutable -> asio::awaitable<bool> { auto maybeSock = co_await CoAwaitClientConnection(); if (maybeSock.has_value()) { co_return ReceiveFile(maybeSock.value(), filePath, _numBytes); } co_return false; }, asio::use_awaitable); co_return result; }
注意:此时调用这个函数的地方也需要是协程,或者用asio::sync_wait来同步获取结果。
方案2:保持外层为普通函数,用asio::sync_wait同步获取协程结果
如果你需要保持ConnectAndTransferFile是普通函数(返回bool),可以用asio::sync_wait来等待协程完成并获取结果,不需要手动调用io_context::run():
bool FileTransferBehaviour::ConnectAndTransferFile(const std::string& _sender, const std::string& _filePath, size_t _numBytes) { auto coroutine = [filePath = _filePath, _numBytes, this]() mutable -> asio::awaitable<bool> { auto maybeSock = co_await CoAwaitClientConnection(); if (maybeSock.has_value()) { co_return ReceiveFile(maybeSock.value(), filePath, _numBytes); } co_return false; }; return asio::sync_wait(asio::co_spawn(m_ioContext, std::move(coroutine), asio::use_awaitable)); }
这个方案中,asio::sync_wait会自动运行io_context直到协程完成,不需要手动调用restart()和run()。
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

