Address bind_handler ambiguous overload error when boost/bind/std_placeholders.hpp is included (#2638)

* Address bind_handler ambiguous overload error when boost/bind/std_placeholders.hpp is included

Previously, the implementation of bind_handler made the assumption
that the trait boost::is_placeholder would be false for types
corresponding to values in the std::placeholders namespace.

However, boost/bind commit c85b31e3d200dda2a73cf0027a82c6d8e29066f8,
`Support use of standard placeholders with boost::bind`, added a new
header, boost/bind/std_placeholders.hpp, which adds specializations to
 boost::is_placeholder for std::placeholders types.

When this header is included before a use of boost::bind_handler, it
results in compiler errors like the following, due to an internal
helper function having overloads for
enable_if<boost::is_placeholder...> and
enable_if<std::is_placeholder...>, which were previously assumed to be
mutually exclusive, but for which both conditions now are true:

../../../boost/beast/core/detail/bind_handler.hpp:126:18: error: call of overloaded 'extract(std::_Placeholder<1>, boost::beast::detail::tuple<int&&>)' is ambiguous
  126 |         h(extract(detail::get<S>(std::move(args)),
      |           ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  127 |             std::forward<ValsTuple>(vals))...);
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This header is included in boost/bind/bind.hpp, and is transitively
included by headers in many boost libraries including:

algorithm
asio
atomic
graph
msm
multi_index
property_tree
ptr_container
python
signals2
test
thread

Making it possible that an include from one of these libraries will
randomly cause bind_handler to fail to compile.

This change addresses the issue by eliminating one of the ambiguous
overloads and ensuring that boost/bind/std_placeholders.hpp is
included in the bind_handler implementation file, so that the
enable_if<boost::is_placeholder...> overload can handle both
boost::placeholders and std::placeholders values. It also explicitly
adds a boost/bind/std_placeholders.hpp include to the bind_handler
unit test to prevent this issue from regressing.

* Address boost/bind/std_placeholders.hpp feature guards

boost/bind/std_placeholders.hpp has the following feature guards:

if !defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) && !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS)

If this check fails, it will not detect std::placeholders values as
placeholders, making the previous solution fail.

This update restores the std::is_placeholder overload and adjusts the
SFINAE for the boost::is_placeholder overload so that it triggers only
if std::is_placeholder is false, making bind_handler work regardless
of whether std_placeholders.hpp's feature guard applies.

---------

Co-authored-by: Edward Nolan <enolan@maystreet.com>
This commit is contained in:
Edward Nolan
2023-02-17 00:50:04 -05:00
committed by GitHub
parent 341ac7591b
commit 8dc6daa507
2 changed files with 5 additions and 1 deletions

View File

@ -20,6 +20,7 @@
#include <boost/asio/handler_invoke_hook.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/mp11/integer_sequence.hpp>
#include <boost/bind/std_placeholders.hpp>
#include <boost/is_placeholder.hpp>
#include <functional>
#include <type_traits>
@ -85,7 +86,9 @@ class bind_wrapper
static
typename std::enable_if<
boost::is_placeholder<typename
std::decay<Arg>::type>::value != 0,
std::decay<Arg>::type>::value != 0 &&
std::is_placeholder<typename
std::decay<Arg>::type>::value == 0,
tuple_element<boost::is_placeholder<
typename std::decay<Arg>::type>::value - 1,
Vals>>::type&&

View File

@ -23,6 +23,7 @@
#include <boost/asio/post.hpp>
#include <boost/asio/strand.hpp>
#include <boost/bind/placeholders.hpp>
#include <boost/bind/std_placeholders.hpp>
#include <boost/core/exchange.hpp>
#include <memory>
#include <string>