Clang 告诉我,从带有完成标记
boost::beast::http::async_write
的 boost::asio::as_tuple(boost::asio::deferred)
的返回值到 awaitable<tuple<boost::system::error_code, unsigned long>>
之间没有可行的转换:
error: no viable conversion from returned value of type 'decltype(enable_if_t<enable_if_t<detail::are_completion_signatures<void (error_code, unsigned long)>::value, detail::async_result_has_initiate_memfn<as_tuple_t<deferred_t>, void (error_code, unsigned long)>>::value, async_result<decay_t<as_tuple_t<deferred_t>>, void (error_code, unsigned long)>>::initiate(static_cast<boost::beast::http::detail::run_write_msg_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp>> &&>(initiation), static_cast<boost::asio::as_tuple_t<boost::asio::deferred_t> &&>(token), static_cast<const boost::beast::http::message<false, boost::beast::http::basic_string_body<char>> *&&>(args), static_cast<std::integral_constant<bool, true> &&>(args)))' (aka 'deferred_async_operation<void (std::tuple<boost::system::error_code, unsigned long>), boost::asio::async_result<boost::asio::as_tuple_t<boost::asio::deferred_t>, void (boost::system::error_code, unsigned long)>::init_wrapper<boost::beast::http::detail::run_write_msg_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::any_io_executor>>>, const boost::beast::http::message<false, boost::beast::http::basic_string_body<char, std::char_traits<char>, std::allocator<char>>, boost::beast::http::basic_fields<std::allocator<char>>> *, std::integral_constant<bool, true>>') to function return type 'boost::asio::awaitable<std::tuple<boost::system::error_code, std::size_t>>' (aka 'awaitable<tuple<boost::system::error_code, unsigned long>>')
179 |return boost::beast::http::async_write(stream, typed_message, boost::asio::as_tuple(boost::asio::deferred));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
所讨论的函数如下所示:
template<typename stream_t>
boost::asio::awaitable<void> response_worker(boost::asio::experimental::channel<void(boost::system::error_code, http_response_t)> &channel, stream_t &stream)
{
while (true) {
boost::system::error_code ec;
std::variant<
boost::beast::http::response<boost::beast::http::string_body>,
boost::beast::http::response<boost::beast::http::empty_body>,
boost::beast::http::response<boost::beast::http::dynamic_body>,
boost::beast::http::response<boost::beast::http::file_body>,
boost::beast::http::response<boost::beast::http::buffer_body>>
message = co_await channel.async_receive(boost::asio::redirect_error(boost::asio::deferred, ec));
if (ec == boost::asio::error::eof) {
channel.close();
co_return;
}
const auto [ec2, transferred] = co_await std::visit(
[&stream](auto &typed_message) -> boost::asio::awaitable<std::tuple<boost::system::error_code, std::size_t>> {
return boost::beast::http::async_write(stream, typed_message, boost::asio::as_tuple(boost::asio::deferred));
},
message);
//error handling
}
}
这用于编译,我对错误消息感到非常困惑,我的代码中是否有错误,或者我的 clang 安装是否比我想象的更糟糕(libclang 没有正确获取标头搜索意味着我必须添加
-I/usr/lib/clang/19/include
作为编译器标志(如果我理解正确的话)?
读取编译器消息:
error: no viable conversion from returned value of type 'decltype(...)` (aka
deferred_async_operation<
void(std::tuple<boost::system::error_code, unsigned long>),
asio::async_result<asio::as_tuple_t<asio::deferred_t>,
void(boost::system::error_code, unsigned long)>::
init_wrapper<http::detail::run_write_msg_op<
asio::basic_stream_socket<asio::ip::tcp, asio::any_io_executor>>>,
http::message<
false, http::basic_string_body<char, std::char_traits<char>, std::allocator<char>>,
http::basic_fields<std::allocator<char>>> const*,
std::integral_constant<bool, true>>'
)
to function return type
'asio::awaitable<std::tuple<boost::system::error_code, std::size_t>>'
return http::async_write(stream, typed_message,
asio::as_tuple(asio::deferred));
看起来您可能已从
asio::use_awaitable
(确实返回可等待的 Promise 类型)更改为 asio::deferred
(这导致延迟的异步操作)。
这很好,因为
这意味着您必须“等待”延迟操作才能获得兼容的返回类型。另请注意,最近的 Asio 版本包含了令牌适配器的部分应用程序,因此您可以像这样拼写它:
住在Coliru
while (true) {
if (auto [ec, message] = co_await channel.async_receive(asio::as_tuple); ec == asio::error::eof) {
co_return channel.close();
} else if (auto [ec, transferred] = co_await std::visit(
[&](auto& typed_message) -> asio::awaitable<std::tuple<error_code, std::size_t>> {
co_return co_await async_write(stream, typed_message, asio::as_tuple);
},
message);
ec.failed()) //
{
// error handling
} else {
//success handling
}
}
坚持住
键入擦除响应。支持所有 message<>
实例的实现称为
http::message_generator
。例如:
#include <boost/asio.hpp>
#include <boost/asio/experimental/channel.hpp>
#include <boost/beast.hpp>
namespace asio = boost::asio;
namespace http = boost::beast::http;
using http_response_t = std::optional<http::message_generator>;
using channel_t = asio::experimental::channel<void(boost::system::error_code, http_response_t)>;
template <typename stream_t> asio::awaitable<void> response_worker(channel_t& channel, stream_t& stream) {
using boost::beast::error_code;
while (true) {
if (auto [ec, response] = co_await channel.async_receive(asio::as_tuple); ec == asio::error::eof) {
co_return channel.close();
} else if (response.has_value()) {
if (auto [ec, transferred] =
co_await boost::beast::async_write(stream, std::move(*response), asio::as_tuple);
ec.failed()) //
{
// error handling
} else {
// success handling
}
}
}
}
int main() {
asio::io_context io_context;
asio::ip::tcp::socket socket(io_context); // TODO connect
channel_t channel(io_context);
co_spawn(io_context, response_worker(channel, socket), asio::detached);
io_context.run();
}