c++ - 为什么 Boost Variant 使用模板构造函数而不是 boost::beast::websocket::stream 的移动构造函数?
问题描述
我正在尝试将boost::beast::websocket::stream<T>
(针对 2 个特定T
的)包装在 aboost::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 不提供.openssl 所需的openssl boost/asio/ssl.hpp
。
Per hereboost::variant
应该接受并T &&
使用它在T
内部实例化。
Per here确实boost::beast::websocket::stream
有一个移动构造函数。
移动构造函数更具体,那么为什么编译器会选择stream<...>
第一个注释中所示的可变参数构造函数()?
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。
解决方案
我忽略的关键信息在以下描述中boost::beast::websocket::stream::stream(stream&&)
:
如果
NextLayer
是 moveconstructible,此函数将从现有流中移动构造一个新流。
事实证明,它boost::asio::ssl::stream
是不可移动构造的,因此stream
没有生成默认的移动构造函数。在引用boost bugtracker 的chriskohlhoff/asio#124中有一个开放的问题可以使ssl::stream
move 可构造。
那么问题的解决方案是使用 的移动构造实现,就像这里ssl::stream
的 Beast 示例中提供的那样,看起来它可能在更高版本的 Beast 中可用(不在 1.67.0 中)。boost/beast/experimental/core/ssl_stream.hpp
推荐阅读
- solr - 为什么 Solr 7.4 中的 Solr Cloud 在我们进行迁移后仍然报告我们的旧 IP
- excel - 生成随机数时循环替换重复项
- r - 如何将变量/矩阵/列表/...从一个 r 会话快速传递到另一个会话?
- azure - 通过 GitHub Actions (.yml) 部署 Azure 静态 Web 应用程序在私有 npm 包上出现 404 错误
- ios - Swift 包中的 UI 元素
- ecmascript-6 - ES6 过滤对象数组,检索空数组或不包含特定值的字段
- file-upload - 如何使用 Python 请求库(使用 CRLF 字符)发送图像二进制文件的多部分/表单数据?
- python - 如何从包含另一个文件列表中的字符串的文本文件中提取行?
- reactjs - 为材料表的标题属性添加图标
- node.js - windows build tool 安装卡住,更多信息向下