Boost.Asio栈式协程编译报错:async_result无completion_handler_type类型
问题描述
我在Ubuntu22.04、GCC9.2、Boost1.81环境下,尝试编写一个可通过boost::spawn调用的栈式协程。这个协程内部启动线程,等待线程完成后获取其生成的整数值作为协程返回值,但遇到了编译错误。
代码实现
// TestAsync.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <boost/asio/spawn.hpp> #include <boost/asio.hpp> #include <boost/thread/future.hpp> template<typename CompletionToken> BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::system::error_code, int)) async_do_something(BOOST_ASIO_MOVE_ARG(CompletionToken) token) { boost::asio::async_completion<CompletionToken, void(boost::system::error_code, int)> completion(token); boost::async(boost::launch::async, [handler = completion.completion_handler]() mutable { boost::system::error_code ec; int result = 0; // 执行操作,并拿到result或ec... std::this_thread::sleep_for(std::chrono::seconds(5)); result = 100; auto executor = boost::asio::get_associated_executor(handler); boost::asio::dispatch(executor, [ec, handler, result]() mutable { handler(ec, result); }); }); return completion.result.get(); } void MyCoroutine(boost::asio::yield_context yield) { std::cout << "进入MyCoroutine" << std::endl; boost::system::error_code ec; int n = async_do_something(yield[ec]); if (ec) std::cerr << ec.message() << std::endl; else std::cout << n << std::endl; std::cout << "离开MyCoroutine" << std::endl; } int main() { boost::asio::io_context ioc; boost::asio::spawn(ioc, MyCoroutine); ioc.run(); }
编译命令
g++ -c -I../boost_1_81_0 main.cpp
编译错误信息
In file included from ../boost_1_81_0/boost/asio/detail/handler_type_requirements.hpp:53, from ../boost_1_81_0/boost/asio/impl/execution_context.hpp:18, from ../boost_1_81_0/boost/asio/execution_context.hpp:409, from ../boost_1_81_0/boost/asio/any_io_executor.hpp:23, from ../boost_1_81_0/boost/asio/spawn.hpp:19, from main.cpp:5: ../boost_1_81_0/boost/asio/async_result.hpp: In instantiation of ‘struct boost::asio::async_completion<boost::asio::basic_yield_context<boost::asio::any_io_executor>, void(boost::system::error_code, int)>’: main.cpp:14:87: required from ‘typename boost::asio::async_result<typename std::decay<_Tp>::type, void(boost::system::error_code, int)>::return_type async_do_something(CompletionToken&&) [with CompletionToken = boost::asio::basic_yield_context<boost::asio::any_io_executor>; typename boost::asio::async_result<typename std::decay<_Tp>::type, void(boost::system::error_code, int)>::return_type = int]’ main.cpp:38:38: required from here ../boost_1_81_0/boost/asio/async_result.hpp:651:9: error: no type named ‘completion_handler_type’ in ‘class boost::asio::async_result<boost::asio::basic_yield_context<boost::asio::any_io_executor>, void(boost::system::error_code, int)>’ 651 | completion_handler_type; | ^~~~~~~~~~~~~~~~~~~~~~~ ../boost_1_81_0/boost/asio/async_result.hpp:684:62: error: no type named ‘completion_handler_type’ in ‘class boost::asio::async_result<boost::asio::basic_yield_context<boost::asio::any_io_executor>, void(boost::system::error_code, int)> ’ 684 | completion_handler_type&, completion_handler_type>::type completion_handler; | ^~~~~~~~~~~~~~~~~~ main.cpp: In instantiation of ‘typename boost::asio::async_result<typename std::decay<_Tp>::type, void(boost::system::error_code, int)>::return_type async_do_something(CompletionToken&&) [with CompletionToken = boost::asio::basic_yield_context<boost::asio::any_io_executor>; typename boost::asio::async_result<typename std::decay<_Tp>::type, void(boost::system::error_code, int)>::return_type = int]’: main.cpp:38:38: required from here main.cpp:16:59: error: ‘struct boost::asio::async_completion<boost::asio::basic_yield_context<boost::asio::any_io_executor>, void(boost::system::error_code, int)>’ has no member named ‘completion_handler’; did you mean ‘completion_handler_type’? 16 | boost::async(boost::launch::async, [handler = completion.completion_handler]() mutable | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ | completion_handler_type main.cpp:32:27: error: ‘class boost::asio::async_result<boost::asio::basic_yield_context<boost::asio::any_io_executor>, void(boost::system::error_code, int)>’ has no member named ‘get’ 32 | return completion.result.get();
问题原因及修复方案
错误根源在于boost::asio::yield_context作为CompletionToken时,async_completion的使用方式不符合Asio的协程适配规则。yield_context并非传统回调handler,它通过async_result直接挂起协程,不需要手动获取completion_handler,也不能调用get()方法。
推荐使用Asio官方推荐的async_compose来封装异步操作,这种方式能完美适配各种CompletionToken类型(包括协程、future、普通回调)。修改后的代码如下:
#include <iostream> #include <boost/asio/spawn.hpp> #include <boost/asio.hpp> #include <boost/thread/future.hpp> #include <boost/asio/async_compose.hpp> template<typename CompletionToken> auto async_do_something(CompletionToken&& token) { namespace asio = boost::asio; return asio::async_compose<CompletionToken, void(boost::system::error_code, int)>( [](auto&& self) { boost::async(boost::launch::async, [self = std::move(self)]() mutable { boost::system::error_code ec; int result = 100; std::this_thread::sleep_for(std::chrono::seconds(5)); auto executor = asio::get_associated_executor(self); asio::dispatch(executor, [ec, self = std::move(self), result]() mutable { std::move(self)(ec, result); }); }); }, token, nullptr // 无默认执行器,使用handler关联的执行器 ); } void MyCoroutine(boost::asio::yield_context yield) { std::cout << "进入MyCoroutine" << std::endl; boost::system::error_code ec; int n = async_do_something(yield[ec]); if (ec) std::cerr << ec.message() << std::endl; else std::cout << n << std::endl; std::cout << "离开MyCoroutine" << std::endl; } int main() { boost::asio::io_context ioc; boost::asio::spawn(ioc, MyCoroutine); ioc.run(); }
关键修改点说明
- 使用
boost::asio::async_compose封装异步操作,这是Asio编写异步接口的标准范式,自动处理不同CompletionToken的适配逻辑。 - 不再直接操作
async_completion内部成员,而是通过async_compose提供的操作对象传递结果,避免类型不匹配问题。 - 确保handler在其关联的执行器上下文中调用,避免跨线程调用引发的线程安全风险。
内容的提问来源于stack exchange,提问作者travaller2
相关产品推荐
相关产品推荐

