I want to understand why when creating two ssl_streams wrapping different objects for the tcp layer, I get the following compilation errors:
------ Build started: Project: test, Configuration: Debug x64 ------
>Microsoft (R) C/C++ Optimizing Compiler Version 19.22.27905 for x64
>Copyright (C) Microsoft Corporation. All rights reserved.
>cl /c /I"D:\workspace\openssl-static\openssl-OpenSSL_1_1_1a\openssl-OpenSSL_1_1_1a\include" /ID:\workspace\boost\VS19\boost_1_70_0 /Zi /W3 /WX- /diagnostics:column /Od /Ob0 /D WIN32 /D _WINDOWS /D _WIN32_WINNT=0x0600 /D _SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING /D "CMAKE_INTDIR=\"Debug\"" /D _MBCS /Gm- /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Zc:inline /GR /std:c++17 /Fo"test.dir\Debug\\" /Fd"test.dir\Debug\vc142.pdb" /Gd /TP /errorReport:prompt D:\workspace\main.cpp
>main.cpp
>D:\workspace\boost\VS19\boost_1_70_0\boost/beast/ssl/ssl_stream.hpp(655,5): error C2995: 'void boost::beast::teardown(boost::beast::role_type,boost::beast::ssl_stream<NextLayer> &,boost::system::error_code &)': function template has already been defined
>D:\workspace\boost\VS19\boost_1_70_0\boost/beast/ssl/ssl_stream.hpp(655): message : see declaration of 'boost::beast::teardown'
>D:\workspace\main.cpp(12): message : see reference to class template instantiation 'boost::beast::ssl_stream<boost::asio::ip::tcp::socket>' being compiled
>D:\workspace\boost\VS19\boost_1_70_0\boost/beast/ssl/ssl_stream.hpp(668,5): error C2995: 'void boost::beast::async_teardown(boost::beast::role_type,boost::beast::ssl_stream<NextLayer> &,TeardownHandler &&)': function template has already been defined
>D:\workspace\boost\VS19\boost_1_70_0\boost/beast/ssl/ssl_stream.hpp(668): message : see declaration of 'boost::beast::async_teardown'
>Done building project "test.vcxproj" -- FAILED.
All errors disappear if both streams have the same template parameter (that is, either both have a boost::beast::tcp_stream or boost::asio::ip::tcp::socket).
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/beast/core/tcp_stream.hpp>
#include <boost/beast/ssl/ssl_stream.hpp>
int main() {
boost::asio::io_context ioc;
boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23_client);
ctx.set_default_verify_paths();
boost::beast::ssl_stream<boost::beast::tcp_stream> stream_1(ioc, ctx);
boost::beast::ssl_stream<boost::asio::ip::tcp::socket> stream_2(ioc, ctx);
}
I want to understand if this is a bug, or desired behavior. If the second, it would be great if someone explained to me why. Also, I would like to better understand in what cases it's worth using the tcp_stream, and in which the socket.
I think It's a bug/QOI issue in Beast. It declares template friend functions
inside the class declaration, i.e. teardown
.
But the template friends don't depend on all the class template template arguments so the next instantation of ssl_stream<>
with other template arguments defines the same template friend function.
The simple fix would be to make the definition out-of-class and the friend declaration only in the class body.
So, it becomes:
template<class NextLayer>
class ssl_stream
: public net::ssl::stream_base
{
// ... many lines snipped ...
#if ! BOOST_BEAST_DOXYGEN
template<class SyncStream>
friend
void
teardown(
boost::beast::role_type role,
ssl_stream<SyncStream>& stream,
boost::system::error_code& ec);
template<class AsyncStream, class TeardownHandler>
friend
void
async_teardown(
boost::beast::role_type role,
ssl_stream<AsyncStream>& stream,
TeardownHandler&& handler);
#endif
};
template<class SyncStream>
static inline void
teardown(
boost::beast::role_type role,
ssl_stream<SyncStream>& stream,
boost::system::error_code& ec)
{
// Just forward it to the underlying ssl::stream
using boost::beast::websocket::teardown;
teardown(role, *stream.p_, ec);
}
template<class AsyncStream, class TeardownHandler>
static inline void
async_teardown(
boost::beast::role_type role,
ssl_stream<AsyncStream>& stream,
TeardownHandler&& handler)
{
// Just forward it to the underlying ssl::stream
using boost::beast::websocket::async_teardown;
async_teardown(role, *stream.p_,
std::forward<TeardownHandler>(handler));
}
I've opened an issue + pull request for thatI was going to open a pull request but it appears that the identical fix (yay) already landed on develop in 1de60a046292dcd42bb0097176e0139ba4ad051b which is in
master
and tagged forboost-1.71.0
andboost-1.71.0.beta1