4 @Copyright Barrett Adair 2015-2017
5 Distributed under the Boost Software License, Version 1.0.
6 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
10 #ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP
11 #define BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP
13 #include <boost/callable_traits/detail/config.hpp>
14 #include <boost/callable_traits/detail/forward_declarations.hpp>
15 #include <boost/callable_traits/detail/utility.hpp>
16 #include <type_traits>
19 namespace boost { namespace callable_traits { namespace detail {
22 struct can_dereference_t
28 static std::int8_t test(
29 check<typename std::remove_reference<decltype(*std::declval<U>())>::type>*
33 static std::int16_t test(...);
35 static constexpr const bool value =
36 sizeof(test<T>(nullptr)) == sizeof(std::int8_t);
39 //returns std::true_type for pointers and smart pointers
41 using can_dereference = std::integral_constant<bool,
42 can_dereference_t<T>::value>;
45 template<typename T, typename = std::true_type>
51 struct generalize_t<T, std::integral_constant<bool,
52 can_dereference<T>::value && !is_reference_wrapper<T>::value
54 using type = decltype(*std::declval<T>());
58 struct generalize_t<T, is_reference_wrapper<T>> {
59 using type = decltype(std::declval<T>().get());
62 // When T is a pointer, generalize<T> is the resulting type of the
63 // pointer dereferenced. When T is an std::reference_wrapper, generalize<T>
64 // is the underlying reference type. Otherwise, generalize<T> is T.
66 using generalize = typename generalize_t<T>::type;
68 // handles the member pointer rules of INVOKE
69 template<typename Base, typename T,
70 typename IsBaseOf = std::is_base_of<Base, shallow_decay<T>>,
71 typename IsSame = std::is_same<Base, shallow_decay<T>>>
72 using generalize_if_dissimilar = typename std::conditional<
73 IsBaseOf::value || IsSame::value, T, generalize<T>>::type;
75 template<typename Traits, bool = Traits::is_const_member::value
76 || Traits::is_volatile_member::value
77 || Traits::is_lvalue_reference_member::value
78 || Traits::is_rvalue_reference_member::value>
81 template<typename... Rgs,
82 typename U = typename Traits::type>
83 auto operator()(Rgs&&... rgs) const ->
84 success<decltype(std::declval<U>()(static_cast<Rgs&&>(rgs)...))>;
86 auto operator()(...) const -> substitution_failure;
90 struct test_invoke<function<F>, true /*abominable*/> {
91 auto operator()(...) const -> substitution_failure;
94 template<typename Pmf, bool Ignored>
95 struct test_invoke<pmf<Pmf>, Ignored> {
97 using class_t = typename pmf<Pmf>::class_type;
99 template<typename U, typename... Rgs,
100 typename Obj = generalize_if_dissimilar<class_t, U&&>>
101 auto operator()(U&& u, Rgs&&... rgs) const ->
102 success<decltype((std::declval<Obj>().*std::declval<Pmf>())(static_cast<Rgs&&>(rgs)...))>;
104 auto operator()(...) const -> substitution_failure;
107 template<typename Pmd, bool Ignored>
108 struct test_invoke<pmd<Pmd>, Ignored> {
110 using class_t = typename pmd<Pmd>::class_type;
113 typename Obj = generalize_if_dissimilar<class_t, U&&>>
114 auto operator()(U&& u) const ->
115 success<decltype(std::declval<Obj>().*std::declval<Pmd>())>;
117 auto operator()(...) const -> substitution_failure;
120 template<typename T, typename... Args>
121 struct is_invocable_impl {
122 using traits = detail::traits<T>;
123 using test = detail::test_invoke<traits>;
124 using result = decltype(test{}(::std::declval<Args>()...));
125 using type = std::integral_constant<bool, result::value>;
128 template<typename... Args>
129 struct is_invocable_impl<void, Args...> {
130 using type = std::false_type;
133 template<typename IsInvocable, typename Ret, typename T, typename... Args>
134 struct is_invocable_r_impl {
135 using traits = detail::traits<T>;
136 using test = detail::test_invoke<traits>;
137 using result = decltype(test{}(::std::declval<Args>()...));
138 using type = typename std::is_convertible<typename result::_::type, Ret>::type;
141 template<typename Ret, typename T, typename... Args>
142 struct is_invocable_r_impl<std::false_type, Ret, T, Args...> {
143 using type = std::false_type;
146 }}} // namespace boost::callable_traits::detail
148 #endif // #ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP