为什么boost::beast::http::async_write的token为as_tuple(deferred)的结果不能转换为awaitable<tuple<error_code, size_t>>?

问题描述 投票:0回答:1

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
作为编译器标志(如果我理解正确的话)?

c++20 boost-asio clang++ c++-coroutine boost-beast
1个回答
0
投票

读取编译器消息:

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
(这导致延迟的异步操作)。

这很好,因为

  1. deferred 成为默认完成令牌
  2. 从 Asio 协程框架(可等待的 Promise 类型)内部调用(“转换”)时,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 } }

坚持住

但是,请注意,您不需要对变体响应对象如此笨拙。您可以使用

BuffersGenerator

键入擦除响应。支持所有 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(); }

	
© www.soinside.com 2019 - 2024. All rights reserved.