diff options
Diffstat (limited to 'boost/callable_traits/detail/is_invocable_impl.hpp')
-rw-r--r-- | boost/callable_traits/detail/is_invocable_impl.hpp | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/boost/callable_traits/detail/is_invocable_impl.hpp b/boost/callable_traits/detail/is_invocable_impl.hpp new file mode 100644 index 0000000000..3238865726 --- /dev/null +++ b/boost/callable_traits/detail/is_invocable_impl.hpp @@ -0,0 +1,148 @@ + /*! +@file + +@Copyright Barrett Adair 2015-2017 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +*/ + +#ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP +#define BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP + +#include <boost/callable_traits/detail/config.hpp> +#include <boost/callable_traits/detail/forward_declarations.hpp> +#include <boost/callable_traits/detail/utility.hpp> +#include <type_traits> +#include <utility> + +namespace boost { namespace callable_traits { namespace detail { + + template<typename T> + struct can_dereference_t + { + template<typename> + struct check {}; + + template<typename U> + static std::int8_t test( + check<typename std::remove_reference<decltype(*std::declval<U>())>::type>* + ); + + template<typename> + static std::int16_t test(...); + + static constexpr const bool value = + sizeof(test<T>(nullptr)) == sizeof(std::int8_t); + }; + + //returns std::true_type for pointers and smart pointers + template<typename T> + using can_dereference = std::integral_constant<bool, + can_dereference_t<T>::value>; + + + template<typename T, typename = std::true_type> + struct generalize_t { + using type = T; + }; + + template<typename T> + struct generalize_t<T, std::integral_constant<bool, + can_dereference<T>::value && !is_reference_wrapper<T>::value + >>{ + using type = decltype(*std::declval<T>()); + }; + + template<typename T> + struct generalize_t<T, is_reference_wrapper<T>> { + using type = decltype(std::declval<T>().get()); + }; + + // When T is a pointer, generalize<T> is the resulting type of the + // pointer dereferenced. When T is an std::reference_wrapper, generalize<T> + // is the underlying reference type. Otherwise, generalize<T> is T. + template<typename T> + using generalize = typename generalize_t<T>::type; + + // handles the member pointer rules of INVOKE + template<typename Base, typename T, + typename IsBaseOf = std::is_base_of<Base, shallow_decay<T>>, + typename IsSame = std::is_same<Base, shallow_decay<T>>> + using generalize_if_dissimilar = typename std::conditional< + IsBaseOf::value || IsSame::value, T, generalize<T>>::type; + + template<typename Traits, bool = Traits::is_const_member::value + || Traits::is_volatile_member::value + || Traits::is_lvalue_reference_member::value + || Traits::is_rvalue_reference_member::value> + struct test_invoke { + + template<typename... Rgs, + typename U = typename Traits::type> + auto operator()(Rgs&&... rgs) const -> + success<decltype(std::declval<U>()(static_cast<Rgs&&>(rgs)...))>; + + auto operator()(...) const -> substitution_failure; + }; + + template<typename F> + struct test_invoke<function<F>, true /*abominable*/> { + auto operator()(...) const -> substitution_failure; + }; + + template<typename Pmf, bool Ignored> + struct test_invoke<pmf<Pmf>, Ignored> { + + using class_t = typename pmf<Pmf>::class_type; + + template<typename U, typename... Rgs, + typename Obj = generalize_if_dissimilar<class_t, U&&>> + auto operator()(U&& u, Rgs&&... rgs) const -> + success<decltype((std::declval<Obj>().*std::declval<Pmf>())(static_cast<Rgs&&>(rgs)...))>; + + auto operator()(...) const -> substitution_failure; + }; + + template<typename Pmd, bool Ignored> + struct test_invoke<pmd<Pmd>, Ignored> { + + using class_t = typename pmd<Pmd>::class_type; + + template<typename U, + typename Obj = generalize_if_dissimilar<class_t, U&&>> + auto operator()(U&& u) const -> + success<decltype(std::declval<Obj>().*std::declval<Pmd>())>; + + auto operator()(...) const -> substitution_failure; + }; + + template<typename T, typename... Args> + struct is_invocable_impl { + using traits = detail::traits<T>; + using test = detail::test_invoke<traits>; + using result = decltype(test{}(::std::declval<Args>()...)); + using type = std::integral_constant<bool, result::value>; + }; + + template<typename... Args> + struct is_invocable_impl<void, Args...> { + using type = std::false_type; + }; + + template<typename IsInvocable, typename Ret, typename T, typename... Args> + struct is_invocable_r_impl { + using traits = detail::traits<T>; + using test = detail::test_invoke<traits>; + using result = decltype(test{}(::std::declval<Args>()...)); + using type = typename std::is_convertible<typename result::_::type, Ret>::type; + }; + + template<typename Ret, typename T, typename... Args> + struct is_invocable_r_impl<std::false_type, Ret, T, Args...> { + using type = std::false_type; + }; + +}}} // namespace boost::callable_traits::detail + +#endif // #ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP |