You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:22:08