diff --git a/include/boost/unordered/detail/foa/takes_arg_as_const_reference.hpp b/include/boost/unordered/detail/foa/takes_arg_as_const_reference.hpp index 00b8ab65..fc6a1c02 100644 --- a/include/boost/unordered/detail/foa/takes_arg_as_const_reference.hpp +++ b/include/boost/unordered/detail/foa/takes_arg_as_const_reference.hpp @@ -9,116 +9,68 @@ #ifndef BOOST_UNORDERED_DETAIL_FOA_TAKES_ARG_AS_CONST_REFERENCE_HPP #define BOOST_UNORDERED_DETAIL_FOA_TAKES_ARG_AS_CONST_REFERENCE_HPP -#include -#include #include #include - -/* VS warns when a pp function is directly called with an empty arg */ -#define BOOST_UNORDERED_EMPTY_PP_ARG() +#include namespace boost{ namespace unordered{ namespace detail{ namespace foa{ -template -struct remove_noexcept{using type=Sig;}; +static constexpr bool noexcept_is_part_of_signature= + !std::is_same::value; -template -using remove_noexcept_t=typename remove_noexcept::type; +template +std::false_type has_1st_arg(Sig); -template -struct remove_noexcept - {using type=R(Args...);}; +template +std::true_type has_1st_arg(R(*)(Arg,Args...)); -template -struct remove_noexcept - {using type=R(Args...,...);}; +template< + typename Arg,typename R,typename... Args, + bool dependent_value=false, + typename std::enable_if< + noexcept_is_part_of_signature||dependent_value>::type* =nullptr +> +std::true_type has_1st_arg(R(*)(Arg,Args...)noexcept); -template -struct remove_noexcept - {using type=R(&)(Args...);}; +template +std::true_type has_1st_arg(R(*)(Arg,Args...,...)); -template -struct remove_noexcept - {using type=R(&)(Args...,...);}; +template< + typename Arg,typename R,typename... Args, + bool dependent_value=false, + typename std::enable_if< + noexcept_is_part_of_signature||dependent_value>::type* =nullptr +> +std::true_type has_1st_arg(R(*)(Arg,Args...,...)noexcept); -template -struct remove_noexcept - {using type=R(Args...);}; +#define BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(qualifier) \ +template \ +std::true_type has_1st_arg(R(C::*)(Arg,Args...)qualifier); \ + \ +template< \ + typename Arg,typename R,typename C,typename... Args, \ + bool dependent_value=false, \ + typename std::enable_if< \ + noexcept_is_part_of_signature||dependent_value>::type* =nullptr \ +> \ +std::true_type has_1st_arg(R(C::*)(Arg,Args...)qualifier noexcept); \ + \ +template \ +std::true_type has_1st_arg(R(C::*)(Arg,Args...,...)qualifier); \ + \ +template< \ + typename Arg,typename R,typename C,typename... Args, \ + bool dependent_value=false, \ + typename std::enable_if< \ + noexcept_is_part_of_signature||dependent_value>::type* =nullptr \ +> \ +std::true_type has_1st_arg(R(C::*)(Arg,Args...,...)qualifier noexcept); -template -struct remove_noexcept - {using type=R(Args...,...);}; - -#define BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(qualifier) \ -template \ -struct remove_noexcept \ - {using type=R(C::*)(Args...)qualifier;}; \ - \ -template \ -struct remove_noexcept \ - {using type=R(C::*)(Args...,...)qualifier;}; - -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(BOOST_UNORDERED_EMPTY_PP_ARG()) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(volatile) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const volatile) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(&) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const&) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(volatile&) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const volatile&) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(&&) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const&&) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(volatile&&) -BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(const volatile&&) - -#undef BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN - -template -struct has_const_reference_arg:std::false_type{}; - -template -struct has_const_reference_arg< - R(const Arg&,Args...) ->:std::true_type{}; - -template -struct has_const_reference_arg< - R(const Arg&,Args...,...) ->:std::true_type{}; - -template -struct has_const_reference_arg< - R(&)(const Arg&,Args...) ->:std::true_type{}; - -template -struct has_const_reference_arg< - R(&)(const Arg&,Args...,...) ->:std::true_type{}; - -template -struct has_const_reference_arg< - R(*)(const Arg&,Args...) ->:std::true_type{}; - -template -struct has_const_reference_arg< - R(*)(const Arg&,Args...,...) ->:std::true_type{}; - -#define BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(qualifier) \ -template \ -struct has_const_reference_arg< \ - R(C::*)(const Arg&,Args...)qualifier \ ->:std::true_type{}; \ - \ -template \ -struct has_const_reference_arg< \ - R(C::*)(const Arg&,Args...,...)qualifier \ ->:std::true_type{}; +/* VS warns when a pp function is directly called with an empty arg */ +#define BOOST_UNORDERED_EMPTY_PP_ARG() BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(BOOST_UNORDERED_EMPTY_PP_ARG()) BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const) @@ -133,66 +85,42 @@ BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const&&) BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(volatile&&) BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const volatile&&) +#undef BOOST_UNORDERED_EMPTY_PP_ARG #undef BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN /* Detects if f(x) takes x as a const reference. From an implementation * technique by Kenneth Gorking. * Requires: F is invocable with an Arg&. - * takes_arg_as_const_reference implemented with an auxiliary - * takes_arg_as_const_reference0 base because VS2015 erroneously matches - * &F::operator() for templated call operators. */ -template +template struct takes_arg_as_const_reference0: - has_const_reference_arg>{}; +decltype(has_1st_arg(std::declval())){}; template struct takes_arg_as_const_reference0< F,Arg, - boost::void_t + boost::void_t< + decltype(has_1st_arg(&F::template operator())) + > >: -takes_arg_as_const_reference0< - decltype(&F::operator()),Arg ->{}; +decltype(has_1st_arg(&F::template operator())){}; template struct takes_arg_as_const_reference:takes_arg_as_const_reference0{}; -#if BOOST_WORKAROUND(BOOST_MSVC,<1920) -/* VS2017 and older issue a C3517 error when trying to obtain the type of - * an instantiation of a function template with deduced return type if - * the instantiation has not been evaluated before. Passing through this - * function solves the problem. Left as a VS-specific workaround because - * old GCC versions seem to have problems with it. - */ - -template T force_evaluation(T); - template struct takes_arg_as_const_reference< F,Arg, - boost::void_t))> + boost::void_t< + decltype(has_1st_arg(&F::operator())) + > >: -takes_arg_as_const_reference< - decltype(force_evaluation(&F::template operator())),Arg ->{}; -#else -template -struct takes_arg_as_const_reference< - F,Arg, - boost::void_t)> ->: -takes_arg_as_const_reference< - decltype(&F::template operator()),Arg ->{}; -#endif +decltype(has_1st_arg(&F::operator())){}; } /* namespace foa */ } /* namespace detail */ } /* namespace unordered */ } /* namespace boost */ -#undef BOOST_UNORDERED_EMPTY_PP_ARG - #endif diff --git a/test/cfoa/takes_arg_as_cref_tests.cpp b/test/cfoa/takes_arg_as_cref_tests.cpp index 828d1fab..2cfa1b05 100644 --- a/test/cfoa/takes_arg_as_cref_tests.cpp +++ b/test/cfoa/takes_arg_as_cref_tests.cpp @@ -59,17 +59,17 @@ struct f46 { template void operator()( Arg& ) const noexcept; }; struct f47 { template void operator()( Arg ); }; struct f48 { template void operator()( Arg ) const; }; struct f49 { template void operator()( Arg ) const noexcept; }; -struct f50 // expected false negative -{ - void operator()( const int& ); - template void operator()( Arg& ); -}; -struct f51 // expected false negative +struct f50 { void operator()( const int& ); void operator()( char* ); }; -using f52=void; // detection doesn't crash even if requirements violated +struct f51 // expected false negative +{ + void operator()( const int& ); + template void operator()( Arg& ); +}; +using f52=int; // detection doesn't crash even if requirements violated int main() { @@ -159,7 +159,7 @@ int main() BOOST_TEST(( !takes_arg_as_const_reference::value )); BOOST_TEST(( !takes_arg_as_const_reference::value )); BOOST_TEST(( !takes_arg_as_const_reference::value )); - BOOST_TEST(( !takes_arg_as_const_reference::value )); + BOOST_TEST(( takes_arg_as_const_reference::value )); BOOST_TEST(( !takes_arg_as_const_reference::value )); BOOST_TEST(( !takes_arg_as_const_reference::value )); BOOST_TEST(( takes_arg_as_const_reference::value ));