co_await boost asio 协程中的自定义等待程序
co_await custom awaiter in boost asio coroutine
我目前正在尝试将新的 C++20 协程与 boost::asio 一起使用。但是,我正在努力寻找如何实现自定义可等待函数(例如 boost::asio::read_async)。我要解决的问题如下:
我有一个连接对象,我可以在其中发出多个请求并为响应注册回调。不能保证响应按请求的顺序到达。我尝试用自定义等待包装回调,但是我无法在协程中 co_await 这个,因为 boost::asio::awaitable.[=15= 中我的等待类型没有 await_transform ]
我尝试将回调包装到可等待对象中的代码改编自此处:
https://books.google.de/books?id=tJIREAAAQBAJ&pg=PA457
auto async_request(const request& r)
{
struct awaitable
{
client* cli;
request req;
response resp{};
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> h)
{
cli->send(req, [this, h](const response& r)
{
resp = r;
h.resume();
});
}
auto await_resume()
{
return resp;
}
};
return awaitable{this, r};
}
我试过像这样调用 boost 协程:
boost::asio::awaitable<void> network::sts::client::connect()
{
//...
auto res = co_await async_request(make_sts_connect());
//...
}
给我以下错误:
error C2664: 'boost::asio::detail::awaitable_frame_base<Executor>::await_transform::result boost::asio::detail::awaitable_frame_base<Executor>::await_transform(boost::asio::this_coro::executor_t) noexcept': cannot convert argument 1 from 'network::sts::client::async_request::awaitable' to 'boost::asio::this_coro::executor_t'
有什么方法可以实现这个功能吗?
我实际上设法找到了解决方案。这样做的方法是使用 boost::asio::async_initiate
构造一个延续处理程序,并将处理程序默认为 boost::use_awaitable
。作为一个额外的好处,通过简单地为处理程序使用模板参数,将它与另一个异步函数匹配是微不足道的。
template<typename ResponseHandler = boost::asio::use_awaitable_t<>>
auto post(const request& req, ResponseHandler&& handler = {})
{
auto initiate = [this]<typename Handler>(Handler&& self, request req) mutable
{
send(req, [self = std::make_shared<Handler>(std::forward<Handler>(self))](const response& r)
{
(*self)(r);
});
};
return boost::asio::async_initiate<
ResponseHandler, void(const response&)>(
initiate, handler, req
);
}
这里唯一的问题是 std::function 显然没有移动构造,所以我不得不将处理程序包装在 std::shared_ptr
.
中
我目前正在尝试将新的 C++20 协程与 boost::asio 一起使用。但是,我正在努力寻找如何实现自定义可等待函数(例如 boost::asio::read_async)。我要解决的问题如下:
我有一个连接对象,我可以在其中发出多个请求并为响应注册回调。不能保证响应按请求的顺序到达。我尝试用自定义等待包装回调,但是我无法在协程中 co_await 这个,因为 boost::asio::awaitable.[=15= 中我的等待类型没有 await_transform ]
我尝试将回调包装到可等待对象中的代码改编自此处: https://books.google.de/books?id=tJIREAAAQBAJ&pg=PA457
auto async_request(const request& r)
{
struct awaitable
{
client* cli;
request req;
response resp{};
bool await_ready() { return false; }
void await_suspend(std::coroutine_handle<> h)
{
cli->send(req, [this, h](const response& r)
{
resp = r;
h.resume();
});
}
auto await_resume()
{
return resp;
}
};
return awaitable{this, r};
}
我试过像这样调用 boost 协程:
boost::asio::awaitable<void> network::sts::client::connect()
{
//...
auto res = co_await async_request(make_sts_connect());
//...
}
给我以下错误:
error C2664: 'boost::asio::detail::awaitable_frame_base<Executor>::await_transform::result boost::asio::detail::awaitable_frame_base<Executor>::await_transform(boost::asio::this_coro::executor_t) noexcept': cannot convert argument 1 from 'network::sts::client::async_request::awaitable' to 'boost::asio::this_coro::executor_t'
有什么方法可以实现这个功能吗?
我实际上设法找到了解决方案。这样做的方法是使用 boost::asio::async_initiate
构造一个延续处理程序,并将处理程序默认为 boost::use_awaitable
。作为一个额外的好处,通过简单地为处理程序使用模板参数,将它与另一个异步函数匹配是微不足道的。
template<typename ResponseHandler = boost::asio::use_awaitable_t<>>
auto post(const request& req, ResponseHandler&& handler = {})
{
auto initiate = [this]<typename Handler>(Handler&& self, request req) mutable
{
send(req, [self = std::make_shared<Handler>(std::forward<Handler>(self))](const response& r)
{
(*self)(r);
});
};
return boost::asio::async_initiate<
ResponseHandler, void(const response&)>(
initiate, handler, req
);
}
这里唯一的问题是 std::function 显然没有移动构造,所以我不得不将处理程序包装在 std::shared_ptr
.