From 8dc6daa507d012d6d75a66a3711f83c8f14282c4 Mon Sep 17 00:00:00 2001 From: Edward Nolan Date: Fri, 17 Feb 2023 00:50:04 -0500 Subject: [PATCH] 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 and enable_if, 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)' is ambiguous 126 | h(extract(detail::get(std::move(args)), | ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 127 | std::forward(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 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 --- include/boost/beast/core/detail/bind_handler.hpp | 5 ++++- test/beast/core/bind_handler.cpp | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/boost/beast/core/detail/bind_handler.hpp b/include/boost/beast/core/detail/bind_handler.hpp index 76f69a41..8d5c5bbb 100644 --- a/include/boost/beast/core/detail/bind_handler.hpp +++ b/include/boost/beast/core/detail/bind_handler.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -85,7 +86,9 @@ class bind_wrapper static typename std::enable_if< boost::is_placeholder::type>::value != 0, + std::decay::type>::value != 0 && + std::is_placeholder::type>::value == 0, tuple_element::type>::value - 1, Vals>>::type&& diff --git a/test/beast/core/bind_handler.cpp b/test/beast/core/bind_handler.cpp index 92a79e76..cc1fffc9 100644 --- a/test/beast/core/bind_handler.cpp +++ b/test/beast/core/bind_handler.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include