refactored takes_arg_as_const_reference.hpp

This commit is contained in:
joaquintides
2023-07-11 20:08:03 +02:00
parent 33f4b04f69
commit 61d92b5847
2 changed files with 66 additions and 138 deletions

View File

@ -9,116 +9,68 @@
#ifndef BOOST_UNORDERED_DETAIL_FOA_TAKES_ARG_AS_CONST_REFERENCE_HPP #ifndef BOOST_UNORDERED_DETAIL_FOA_TAKES_ARG_AS_CONST_REFERENCE_HPP
#define BOOST_UNORDERED_DETAIL_FOA_TAKES_ARG_AS_CONST_REFERENCE_HPP #define BOOST_UNORDERED_DETAIL_FOA_TAKES_ARG_AS_CONST_REFERENCE_HPP
#include <boost/config.hpp>
#include <boost/config/workaround.hpp>
#include <boost/type_traits/make_void.hpp> #include <boost/type_traits/make_void.hpp>
#include <type_traits> #include <type_traits>
#include <utility>
/* VS warns when a pp function is directly called with an empty arg */
#define BOOST_UNORDERED_EMPTY_PP_ARG()
namespace boost{ namespace boost{
namespace unordered{ namespace unordered{
namespace detail{ namespace detail{
namespace foa{ namespace foa{
template<typename Sig> static constexpr bool noexcept_is_part_of_signature=
struct remove_noexcept{using type=Sig;}; !std::is_same<void(*)(),void(*)()noexcept>::value;
template<typename Sig> template<typename Arg,typename Sig>
using remove_noexcept_t=typename remove_noexcept<Sig>::type; std::false_type has_1st_arg(Sig);
template<typename R,typename... Args> template<typename Arg,typename R,typename... Args>
struct remove_noexcept<R(Args...)noexcept> std::true_type has_1st_arg(R(*)(Arg,Args...));
{using type=R(Args...);};
template<typename R,typename... Args> template<
struct remove_noexcept<R(Args...,...)noexcept> typename Arg,typename R,typename... Args,
{using type=R(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<typename R,typename... Args> template<typename Arg,typename R,typename... Args>
struct remove_noexcept<R(&)(Args...)noexcept> std::true_type has_1st_arg(R(*)(Arg,Args...,...));
{using type=R(&)(Args...);};
template<typename R,typename... Args> template<
struct remove_noexcept<R(&)(Args...,...)noexcept> typename Arg,typename R,typename... Args,
{using type=R(&)(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<typename R,typename... Args> #define BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(qualifier) \
struct remove_noexcept<R(*)(Args...)noexcept> template<typename Arg,typename R,typename C,typename... Args> \
{using type=R(Args...);}; 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<typename Arg,typename R,typename C,typename... Args> \
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<typename R,typename... Args> /* VS warns when a pp function is directly called with an empty arg */
struct remove_noexcept<R(*)(Args...,...)noexcept> #define BOOST_UNORDERED_EMPTY_PP_ARG()
{using type=R(Args...,...);};
#define BOOST_UNORDERED_REMOVE_NOEXCEPT_MEMFUN(qualifier) \
template<typename R,typename C,typename... Args> \
struct remove_noexcept<R(C::*)(Args...)qualifier noexcept> \
{using type=R(C::*)(Args...)qualifier;}; \
\
template<typename R,typename C,typename... Args> \
struct remove_noexcept<R(C::*)(Args...,...)qualifier 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<typename Sig>
struct has_const_reference_arg:std::false_type{};
template<typename R,typename Arg,typename... Args>
struct has_const_reference_arg<
R(const Arg&,Args...)
>:std::true_type{};
template<typename R,typename Arg,typename... Args>
struct has_const_reference_arg<
R(const Arg&,Args...,...)
>:std::true_type{};
template<typename R,typename Arg,typename... Args>
struct has_const_reference_arg<
R(&)(const Arg&,Args...)
>:std::true_type{};
template<typename R,typename Arg,typename... Args>
struct has_const_reference_arg<
R(&)(const Arg&,Args...,...)
>:std::true_type{};
template<typename R,typename Arg,typename... Args>
struct has_const_reference_arg<
R(*)(const Arg&,Args...)
>:std::true_type{};
template<typename R,typename Arg,typename... Args>
struct has_const_reference_arg<
R(*)(const Arg&,Args...,...)
>:std::true_type{};
#define BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(qualifier) \
template<typename R,typename C,typename Arg,typename... Args> \
struct has_const_reference_arg< \
R(C::*)(const Arg&,Args...)qualifier \
>:std::true_type{}; \
\
template<typename R,typename C,typename Arg,typename... Args> \
struct has_const_reference_arg< \
R(C::*)(const Arg&,Args...,...)qualifier \
>:std::true_type{};
BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(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) 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(volatile&&)
BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const volatile&&) BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN(const volatile&&)
#undef BOOST_UNORDERED_EMPTY_PP_ARG
#undef BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN #undef BOOST_UNORDERED_HAS_CONST_REFERENCE_ARG_MEMFUN
/* Detects if f(x) takes x as a const reference. From an implementation /* Detects if f(x) takes x as a const reference. From an implementation
* technique by Kenneth Gorking. * technique by Kenneth Gorking.
* Requires: F is invocable with an Arg&. * 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<typename F,typename /*Arg*/,typename=void> template<typename F,typename Arg,typename=void>
struct takes_arg_as_const_reference0: struct takes_arg_as_const_reference0:
has_const_reference_arg<remove_noexcept_t<F>>{}; decltype(has_1st_arg<const Arg&>(std::declval<F>())){};
template<typename F,typename Arg> template<typename F,typename Arg>
struct takes_arg_as_const_reference0< struct takes_arg_as_const_reference0<
F,Arg, F,Arg,
boost::void_t<decltype(&F::operator())> boost::void_t<
decltype(has_1st_arg<const Arg&>(&F::template operator()<Arg>))
>
>: >:
takes_arg_as_const_reference0< decltype(has_1st_arg<const Arg&>(&F::template operator()<Arg>)){};
decltype(&F::operator()),Arg
>{};
template<typename F,typename Arg,typename=void> template<typename F,typename Arg,typename=void>
struct takes_arg_as_const_reference:takes_arg_as_const_reference0<F,Arg>{}; struct takes_arg_as_const_reference:takes_arg_as_const_reference0<F,Arg>{};
#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<typename T> T force_evaluation(T);
template<typename F,typename Arg> template<typename F,typename Arg>
struct takes_arg_as_const_reference< struct takes_arg_as_const_reference<
F,Arg, F,Arg,
boost::void_t<decltype(force_evaluation(&F::template operator()<Arg>))> boost::void_t<
decltype(has_1st_arg<const Arg&>(&F::operator()))
>
>: >:
takes_arg_as_const_reference< decltype(has_1st_arg<const Arg&>(&F::operator())){};
decltype(force_evaluation(&F::template operator()<Arg>)),Arg
>{};
#else
template<typename F,typename Arg>
struct takes_arg_as_const_reference<
F,Arg,
boost::void_t<decltype(&F::template operator()<Arg>)>
>:
takes_arg_as_const_reference<
decltype(&F::template operator()<Arg>),Arg
>{};
#endif
} /* namespace foa */ } /* namespace foa */
} /* namespace detail */ } /* namespace detail */
} /* namespace unordered */ } /* namespace unordered */
} /* namespace boost */ } /* namespace boost */
#undef BOOST_UNORDERED_EMPTY_PP_ARG
#endif #endif

View File

@ -59,17 +59,17 @@ struct f46 { template<typename Arg> void operator()( Arg& ) const noexcept; };
struct f47 { template<typename Arg> void operator()( Arg ); }; struct f47 { template<typename Arg> void operator()( Arg ); };
struct f48 { template<typename Arg> void operator()( Arg ) const; }; struct f48 { template<typename Arg> void operator()( Arg ) const; };
struct f49 { template<typename Arg> void operator()( Arg ) const noexcept; }; struct f49 { template<typename Arg> void operator()( Arg ) const noexcept; };
struct f50 // expected false negative struct f50
{
void operator()( const int& );
template<typename Arg> void operator()( Arg& );
};
struct f51 // expected false negative
{ {
void operator()( const int& ); void operator()( const int& );
void operator()( char* ); void operator()( char* );
}; };
using f52=void; // detection doesn't crash even if requirements violated struct f51 // expected false negative
{
void operator()( const int& );
template<typename Arg> void operator()( Arg& );
};
using f52=int; // detection doesn't crash even if requirements violated
int main() int main()
{ {
@ -159,7 +159,7 @@ int main()
BOOST_TEST(( !takes_arg_as_const_reference<f47, int>::value )); BOOST_TEST(( !takes_arg_as_const_reference<f47, int>::value ));
BOOST_TEST(( !takes_arg_as_const_reference<f48, int>::value )); BOOST_TEST(( !takes_arg_as_const_reference<f48, int>::value ));
BOOST_TEST(( !takes_arg_as_const_reference<f49, int>::value )); BOOST_TEST(( !takes_arg_as_const_reference<f49, int>::value ));
BOOST_TEST(( !takes_arg_as_const_reference<f50, int>::value )); BOOST_TEST(( takes_arg_as_const_reference<f50, int>::value ));
BOOST_TEST(( !takes_arg_as_const_reference<f51, int>::value )); BOOST_TEST(( !takes_arg_as_const_reference<f51, int>::value ));
BOOST_TEST(( !takes_arg_as_const_reference<f52, int>::value )); BOOST_TEST(( !takes_arg_as_const_reference<f52, int>::value ));
BOOST_TEST(( takes_arg_as_const_reference<f53, int>::value )); BOOST_TEST(( takes_arg_as_const_reference<f53, int>::value ));