【问题标题】:Why does Boost Variant use the template constructor instead of the move constructor for boost::beast::websocket::stream?为什么 Boost Variant 使用模板构造函数而不是 boost::beast::websocket::stream 的移动构造函数?
【发布时间】:2018-07-31 09:05:27
【问题描述】:

我正在尝试将 boost::beast::websocket::stream<T>(用于 2 个特定的 T)包装在 boost::variant 中,以允许将 TLS ([T = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>]) 和非 TLS ([T = boost::asio::ip::tcp::socket]) websocket 视为相同。我被编译失败卡住了。

我能想到的最简单的失败例子是:

#include <boost/asio/ssl.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/websocket.hpp>
#include <boost/variant.hpp>

using tcp = boost::asio::ip::tcp;
namespace ws = boost::beast::websocket;
namespace ssl = boost::asio::ssl;

using base_ws = boost::variant<
    ws::stream<tcp::socket>, ws::stream<ssl::stream<tcp::socket>>>;

class test
{
 public:
    static void init( tcp::socket &&  socket )
    {
        ssl::context  ctx{ ssl::context::tlsv12_server };
        ws::stream<ssl::stream<tcp::socket>>  s{ std::move( socket ), ctx };
        base_ws{ std::move( s ) };
    }
};

int main()
{}

编译失败并报错:

In file included from /server/src/ws_server.cpp:9:
In file included from /include/boost/beast/websocket.hpp:18:
In file included from /include/boost/beast/websocket/stream.hpp:3455:
/include/boost/beast/websocket/impl/stream.ipp:47:7: error: no matching constructor for initialization of 'boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >'
    : stream_(std::forward<Args>(args)...)
      ^       ~~~~~~~~~~~~~~~~~~~~~~~~
/include/boost/variant/detail/initializer.hpp:122:27: note: in instantiation of function template specialization 'boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> > >::stream<boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> > > >' requested here
                new(dest) value_T( boost::detail::variant::move(operand) );
                          ^
/include/boost/variant/variant.hpp:1687:28: note: in instantiation of member function 'boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::make_initializer_node::apply<boost::mpl::pair<boost::detail::variant::initializer_root, mpl_::int_<0> >, boost::mpl::l_iter<boost::mpl::list2<boost::beast::websocket::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >, boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> > > > > >::initializer_node, mpl_::int_<1> >, boost::mpl::l_iter<boost::mpl::list1<boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> > > > > >::initializer_node::initialize' requested here
              initializer::initialize(
                           ^
/include/boost/variant/variant.hpp:1858:9: note: in instantiation of function template specialization 'boost::variant<boost::beast::websocket::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >, boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> > > >::convert_construct<boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> > > >' requested here
        convert_construct( detail::variant::move(operand), 1L);
        ^
/server/src/ws_server.cpp:372:20: note: in instantiation of function template specialization 'boost::variant<boost::beast::websocket::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >, boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> > > >::variant<boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> > > >' requested here
            return base_ws( std::move( s ) );
                   ^
/include/boost/asio/ssl/stream.hpp:64:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'boost::beast::websocket::stream<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> > >' to 'const boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp> >' for 1st argument
class stream :
      ^
/include/boost/asio/ssl/stream.hpp:98:3: note: candidate constructor template not viable: requires 2 arguments, but 1 was provided
  stream(Arg&& arg, context& ctx)
  ^

我会提供godbolt,但它会超时,而coliru 不提供boost/asio/ssl.hpp 所需的openssl。

根据hereboost::variant 应该接受T &amp;&amp; 并使用它在内部实例化T

根据hereboost::beast::websocket::stream 确实有一个移动构造函数。

移动构造函数更具体,那么为什么编译器会选择第一个注释中指出的可变参数构造函数 (stream&lt;...&gt;)?

boost::beast::websocket::stream<
  boost::asio::ssl::stream<
    boost::asio::basic_stream_socket<boost::asio::ip::tcp>
  >
>::stream<
  boost::beast::websocket::stream<
    boost::asio::ssl::stream<
      boost::asio::basic_stream_socket<boost::asio::ip::tcp>
    >
  >
>

我正在使用 Boost 1.66.0 和 Clang 7。

【问题讨论】:

    标签: c++ boost boost-variant boost-beast


    【解决方案1】:

    我忽略的关键信息在boost::beast::websocket::stream::stream(stream&amp;&amp;)的描述中:

    如果NextLayer 是可移动构造的,此函数将从现有流中移动构造一个新流。

    原来boost::asio::ssl::stream不是move构造函数,所以stream默认的move构造函数没有生成。有一个未解决的问题可以使 ssl::stream 在引用 boost bugtrackerchriskohlhoff/asio#124 中可构造。

    解决问题的方法是使用 ssl::stream 的可移动构造实现,就像 Beast 示例中提供的那样 here,看起来它可以在更高版本的 Beast 中的 boost/beast/experimental/core/ssl_stream.hpp 中获得(不在 1.67.0 中)。

    【讨论】:

      【解决方案2】:

      advanced-server-flex 示例展示了如何使用处理 SSL 和普通 websocket 会话的代码构建服务器,而无需求助于变体:https://github.com/boostorg/beast/blob/c2ecba968c06a22a61c67b8887f5b477bb32a99a/example/advanced/server-flex/advanced_server_flex.cpp#L227

      【讨论】:

      • 谢谢,我确实查看了 flex 服务器代码。就我而言,我提供了一个 pimpl 类,并希望避免接口和 impl 被模板化,因此我将变体作为实现的成员。如果不是这样,我会采用你的方法,因为 1. websocket 接口没有失去灵活性和 2. 没有运行时损失。提供我从gist.github.com/chrahunt/… 继承的功能,然后使用async_read( ws_, buffer_, etc... ) 这样写起来感觉还不错,但我仍然需要分析。
      猜你喜欢
      • 1970-01-01
      • 2015-06-10
      • 1970-01-01
      • 1970-01-01
      • 2013-04-25
      • 2022-01-12
      • 2012-04-29
      • 1970-01-01
      相关资源
      最近更新 更多