尝试为boost.asio封装一个有栈协程异步方法,一直报标题这个错误。给官方提交了bug:no type named ‘completion_handler_type’ in ‘class boost::asio::async_result’ · Issue #1255 · chriskohlhoff/asio · GitHub
好多天没有人回复,昨晚上在stackoverflow上提交了问题,早上查看就有人帮解决了。
先看最初的代码,之前网上能搜到的代码都是类似这种形式,在Boost1.81上编译会报错:
// 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();
}
GCC9.2编译错误信息:
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();
VS2022编译错误信息:
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2039 "completion_handler_type": 不是 "boost::asio::async_result<boost::asio::basic_yield_contextboost::asio::any_io_executor,void (boost::system::error_code,int)>" 的成员 TestAsync D:\library\boost_1_81_0\boost\asio\async_result.hpp 650
错误 C3646 “completion_handler_type”: 未知重写说明符 TestAsync D:\library\boost_1_81_0\boost\asio\async_result.hpp 651
错误 C4430 缺少类型说明符 - 假定为 int。注意: C++ 不支持默认 int TestAsync D:\library\boost_1_81_0\boost\asio\async_result.hpp 651
错误 C2064 项不会计算为接受 2 个参数的函数 TestAsync C:\Users\laf163\Desktop\TestAsync\TestAsync\TestAsync.cpp 23
错误 C2039 "get": 不是 "boost::asio::async_result<boost::asio::basic_yield_contextboost::asio::any_io_executor,void (boost::system::error_code,int)>" 的成员 TestAsync C:\Users\laf163\Desktop\TestAsync\TestAsync\TestAsync.cpp 27
老外提供的修改后的代码:
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/thread/future.hpp>
#include <iostream>
#include <thread>
namespace asio = boost::asio;
template <typename Token>
typename asio::async_result<typename std::decay<Token>::type,
void(boost::system::error_code, int)>::return_type
async_do_something(Token&& token) {
auto init = [](auto handler) {
boost::async(
boost::launch::async,
[handler = std::move(handler), work = make_work_guard(handler)]() mutable {
boost::system::error_code ec;
int result = 0;
std::this_thread::sleep_for(std::chrono::seconds(5));
result = 100;
auto executor = asio::get_associated_executor(handler);
asio::dispatch(executor, [ec, handler = std::move(handler), result]() mutable {
std::move(handler)(ec, result);
});
});
};
return asio::async_initiate<Token, void(boost::system::error_code, int)>(init, token);
}
void MyCoroutine(asio::yield_context yield) {
std::cout << "Enter 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 << "Leave MyCoroutine" << std::endl;
}
int main() {
asio::io_context ioc;
asio::spawn(ioc, MyCoroutine);
ioc.run();
}
详细信息参考:no type named ‘completion_handler_type’ in ‘class boost::asio::async_result’ - Stack Overflow
模型声明和签名可以简化为:
template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void(boost::system::error_code, int)) Token>
auto async_do_something(Token&& token) {
// ......
}
参考官方文档: