Related (but not the problem), I am trying to get a UPnP library to work. It appears to be targeted to Boost 1.71.0. However, my project uses Boost 1.74.0. So I thought it should be fairly easy to migrate.
But it seems that something significant changed with asio's executors in Boost 1.74.0. It's not clear to me what changed or how to migrate from 1.73.x to 1.74.0. I intend to use Boost Asio for additional parts of the project so I need to understand what is happening here.
I think I have trimmed it down to a minimal reproducible code snippet. This snippet compiles fine with Boost 1.73.0 and GCC 5.5.
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/executor.hpp>
namespace net = boost::asio;
using tcp = net::ip::tcp;
void foo(net::executor exec)
{
tcp::resolver r{exec};
}
However, when I change the library to Boost 1.74.0 I then get a compiler error that describes an issue with the executor.
The error appears to be related to the executor changes. If I try to instantiate a tcp::socket or udp::socket or even a local::stream_protocol::socket, they all result in the same error describing executors.
I did a brief search on cpplang slack. One comment thread seemed to suggest to use bind_executor. I don't know what that is, but it didn't solve the problem either. Another comment suggested that the execution_context was needed which also didn't work. There was a lot of discussion about using any_executor but that also doesn't seem to work.
So I thought maybe the release notes might include some instructions for migration.
I saw a paper P0443R13. Maybe I'll read that later but it's far too dense material to get a quick solution.
I also saw two papers P1348R0 and P1393R0 both of which are very terse but doesn't appear to be related to the problem I'm encountering.
The compiler error is described below:
source>:9:25: error: no matching function for call to 'boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(<brace-enclosed initializer list>)'
tcp::resolver r{exec};
^
I understand that the resolver object can't be constructed. The error goes on with several notes and related substitution failure messages
This one clearly describes that it can't convert an execution context to a resolver r-value reference. Makes sense.
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/ip/basic_resolver.hpp:141:3: note: candidate: boost::asio::ip::basic_resolver<InternetProtocol, Executor>::basic_resolver(boost::asio::ip::basic_resolver<InternetProtocol, Executor>&&) [with InternetProtocol = boost::asio::ip::tcp; Executor = boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >]
basic_resolver(basic_resolver&& other)
^
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/ip/basic_resolver.hpp:141:3: note: no known conversion for argument 1 from 'boost::asio::executor' to 'boost::asio::ip::basic_resolver<boost::asio::ip::tcp>&&'
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/ip/basic_resolver.hpp:122:12:
This one describes a template substitution failure. It appears to be related to the executor. I don't understand what the failure is.
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/ip/basic_resolver.hpp:122:12: note: candidate: template<class ExecutionContext> boost::asio::ip::basic_resolver<InternetProtocol, Executor>::basic_resolver(ExecutionContext&, typename std::enable_if<std::is_convertible<ExecutionContext&, boost::asio::execution_context&>::value>::type*)
explicit basic_resolver(ExecutionContext& context,
^
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/ip/basic_resolver.hpp:122:12: note: template argument deduction/substitution failed:
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/ip/basic_resolver.hpp: In substitution of 'template<class ExecutionContext> boost::asio::ip::basic_resolver<InternetProtocol, Executor>::basic_resolver(ExecutionContext&, typename std::enable_if<std::is_convertible<ExecutionContext&, boost::asio::execution_context&>::value>::type*) [with ExecutionContext = boost::asio::executor]':
<source>:9:25: required from here
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/ip/basic_resolver.hpp:122:12: error: no type named 'type' in 'struct std::enable_if<false, void>'
This one also appears to be related to the executor but it can't convert the boost::asio::executor to a boost::asio::execution::any_executor with a bunch of template vomit. This is the constructor that I think should be valid but apparently is not.
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/ip/basic_resolver.hpp:108:12: note: candidate: boost::asio::ip::basic_resolver<InternetProtocol, Executor>::basic_resolver(const executor_type&) [with InternetProtocol = boost::asio::ip::tcp; Executor = boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >; boost::asio::ip::basic_resolver<InternetProtocol, Executor>::executor_type = boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >]
explicit basic_resolver(const executor_type& ex)
^
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/ip/basic_resolver.hpp:108:12: note: no known conversion for argument 1 from 'boost::asio::executor' to 'const executor_type& {aka const boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >&}'
I see Asio does decribe "This new name may break existing code that directly uses the old polymorphic wrapper, executor."
The documentation includes a description of the Proposed Standard Executors. It does describe a compile-definition which appears to be a valid workaround: #define BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT 1. That turns the asio::executor back into what it was before Boost 1.74.0. However, I strongly recommend migrating by changing references of executor to, at least, any_io_executor. Doing so is not fraught without its own perils though.
Simply changing the executor to any_io_executor appears to have solved the immediate problem.
This compiles in Compiler Explorer.
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/executor.hpp>
#include <boost/asio/local/stream_protocol.hpp>
#include <boost/asio/any_io_executor.hpp>
namespace net = boost::asio;
using tcp = net::ip::tcp;
using local = net::local::stream_protocol;
void foo(net::any_io_executor exec)
{
tcp::socket s{exec};
local::socket ls{exec};
tcp::resolver r{exec};
}
However, changing the types in the project resulted in additional compiler errors that were even more difficult to figure out. Ultimately the compiler errors were because I was compiling one translation unit (.cpp file) and fixing the errors only in that translation unit. But that translation unit was #include-ing a header for another translation unit and giving the any_io_executor object to an executor object. For some reason, Boost Asio doesn't emit a useful error message here and the compiler template vomit isn't helpful.
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/executor.hpp>
#include <boost/asio/any_io_executor.hpp>
namespace net = boost::asio;
using tcp = net::ip::tcp;
void baz(net::executor exec);
void foo(net::any_io_executor exec)
{
tcp::resolver r{exec};
baz(exec);
}
The errors are:
In file included from /opt/compiler-explorer/libs/boost_1_74_0/boost/asio/executor.hpp:342:0,
from <source>:2:
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp: In instantiation of 'void boost::asio::executor::impl< <template-parameter-1-1>, <template-parameter-1-2> >::on_work_started() [with Executor = boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >; Allocator = std::allocator<void>]':
<source>:14:1: required from here
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp:79:5: error: 'class boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >' has no member named 'on_work_started'
executor_.on_work_started();
^
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp: In instantiation of 'void boost::asio::executor::impl< <template-parameter-1-1>, <template-parameter-1-2> >::on_work_finished() [with Executor = boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >; Allocator = std::allocator<void>]':
<source>:14:1: required from here
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp:84:5: error: 'class boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >' has no member named 'on_work_finished'
executor_.on_work_finished();
^
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp: In instantiation of 'void boost::asio::executor::impl< <template-parameter-1-1>, <template-parameter-1-2> >::dispatch(boost::asio::executor::function&&) [with Executor = boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >; Allocator = std::allocator<void>; boost::asio::executor::function = boost::asio::detail::executor_function]':
<source>:14:1: required from here
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp:94:5: error: 'class boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >' has no member named 'dispatch'
executor_.dispatch(BOOST_ASIO_MOVE_CAST(function)(f), allocator_);
^
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp: In instantiation of 'void boost::asio::executor::impl< <template-parameter-1-1>, <template-parameter-1-2> >::post(boost::asio::executor::function&&) [with Executor = boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >; Allocator = std::allocator<void>; boost::asio::executor::function = boost::asio::detail::executor_function]':
<source>:14:1: required from here
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp:99:5: error: 'class boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >' has no member named 'post'
executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), allocator_);
^
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp: In instantiation of 'void boost::asio::executor::impl< <template-parameter-1-1>, <template-parameter-1-2> >::defer(boost::asio::executor::function&&) [with Executor = boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >; Allocator = std::allocator<void>; boost::asio::executor::function = boost::asio::detail::executor_function]':
<source>:14:1: required from here
/opt/compiler-explorer/libs/boost_1_74_0/boost/asio/impl/executor.hpp:104:5: error: 'class boost::asio::execution::any_executor<boost::asio::execution::context_as_t<boost::asio::execution_context&>, boost::asio::execution::detail::blocking::never_t<0>, boost::asio::execution::prefer_only<boost::asio::execution::detail::blocking::possibly_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::tracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::outstanding_work::untracked_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::fork_t<0> >, boost::asio::execution::prefer_only<boost::asio::execution::detail::relationship::continuation_t<0> > >' has no member named 'defer'
executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), allocator_);
^
It appears that the compiler is complaining that the new executor is missing some functions:
on_work_started()on_work_finished()dispatch()post()defer()I found one (at the time of this writing) other developer encountering this error. They opted to use the workaround instead of truly solving the problem though. There also appears to be a neat (but less-than-helpful) list of Boost Asio symbols. The key here is noting that on_work_started only shows up for executor, and not for any_io_executor
So the problem is that passing any_io_executor to an executor will cause relatively unintelligible compiler errors. It's basically telling you that you need to completely change all of the types to any_io_executor. It appears to be an all-or-nothing approach. Doing so allowed me to build the library I wanted against Boost 1.74.0. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With