]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
1 | /*! |
2 | @file | |
3 | ||
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) | |
7 | ||
8 | */ | |
9 | ||
10 | #ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP | |
11 | #define BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP | |
12 | ||
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> | |
17 | #include <utility> | |
18 | ||
19 | namespace boost { namespace callable_traits { namespace detail { | |
20 | ||
21 | template<typename T> | |
22 | struct can_dereference_t | |
23 | { | |
24 | template<typename> | |
25 | struct check {}; | |
26 | ||
27 | template<typename U> | |
28 | static std::int8_t test( | |
29 | check<typename std::remove_reference<decltype(*std::declval<U>())>::type>* | |
30 | ); | |
31 | ||
32 | template<typename> | |
33 | static std::int16_t test(...); | |
34 | ||
35 | static constexpr const bool value = | |
36 | sizeof(test<T>(nullptr)) == sizeof(std::int8_t); | |
37 | }; | |
38 | ||
39 | //returns std::true_type for pointers and smart pointers | |
40 | template<typename T> | |
41 | using can_dereference = std::integral_constant<bool, | |
42 | can_dereference_t<T>::value>; | |
43 | ||
44 | ||
45 | template<typename T, typename = std::true_type> | |
46 | struct generalize_t { | |
47 | using type = T; | |
48 | }; | |
49 | ||
50 | template<typename T> | |
51 | struct generalize_t<T, std::integral_constant<bool, | |
52 | can_dereference<T>::value && !is_reference_wrapper<T>::value | |
53 | >>{ | |
54 | using type = decltype(*std::declval<T>()); | |
55 | }; | |
56 | ||
57 | template<typename T> | |
58 | struct generalize_t<T, is_reference_wrapper<T>> { | |
59 | using type = decltype(std::declval<T>().get()); | |
60 | }; | |
61 | ||
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. | |
65 | template<typename T> | |
66 | using generalize = typename generalize_t<T>::type; | |
67 | ||
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; | |
74 | ||
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> | |
79 | struct test_invoke { | |
80 | ||
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)...))>; | |
85 | ||
86 | auto operator()(...) const -> substitution_failure; | |
87 | }; | |
88 | ||
89 | template<typename F> | |
90 | struct test_invoke<function<F>, true /*abominable*/> { | |
91 | auto operator()(...) const -> substitution_failure; | |
92 | }; | |
93 | ||
94 | template<typename Pmf, bool Ignored> | |
95 | struct test_invoke<pmf<Pmf>, Ignored> { | |
96 | ||
97 | using class_t = typename pmf<Pmf>::class_type; | |
98 | ||
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)...))>; | |
103 | ||
104 | auto operator()(...) const -> substitution_failure; | |
105 | }; | |
106 | ||
107 | template<typename Pmd, bool Ignored> | |
108 | struct test_invoke<pmd<Pmd>, Ignored> { | |
109 | ||
110 | using class_t = typename pmd<Pmd>::class_type; | |
111 | ||
112 | template<typename U, | |
113 | typename Obj = generalize_if_dissimilar<class_t, U&&>> | |
114 | auto operator()(U&& u) const -> | |
115 | success<decltype(std::declval<Obj>().*std::declval<Pmd>())>; | |
116 | ||
117 | auto operator()(...) const -> substitution_failure; | |
118 | }; | |
119 | ||
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>; | |
126 | }; | |
127 | ||
128 | template<typename... Args> | |
129 | struct is_invocable_impl<void, Args...> { | |
130 | using type = std::false_type; | |
131 | }; | |
132 | ||
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; | |
139 | }; | |
140 | ||
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; | |
144 | }; | |
145 | ||
146 | }}} // namespace boost::callable_traits::detail | |
147 | ||
148 | #endif // #ifndef BOOST_CLBL_TRTS_IS_INVOCABLE_IMPL_HPP |