| 1 | /*============================================================================= |
| 2 | Copyright (c) 2015 Paul Fultz II |
| 3 | can_be_called.h |
| 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying |
| 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 6 | ==============================================================================*/ |
| 7 | |
| 8 | #ifndef BOOST_HOF_GUARD_CAN_BE_CALLED_H |
| 9 | #define BOOST_HOF_GUARD_CAN_BE_CALLED_H |
| 10 | |
| 11 | #include <boost/hof/config.hpp> |
| 12 | #include <boost/hof/detail/and.hpp> |
| 13 | #include <boost/hof/detail/holder.hpp> |
| 14 | #include <boost/hof/detail/using.hpp> |
| 15 | |
| 16 | namespace boost { namespace hof { namespace detail { |
| 17 | |
| 18 | #if BOOST_HOF_NO_EXPRESSION_SFINAE |
| 19 | struct dont_care |
| 20 | { |
| 21 | dont_care(...); |
| 22 | }; |
| 23 | |
| 24 | template<class T> |
| 25 | struct never_care |
| 26 | { |
| 27 | typedef dont_care type; |
| 28 | }; |
| 29 | |
| 30 | struct cant_be_called_type |
| 31 | {}; |
| 32 | |
| 33 | struct no_type |
| 34 | {}; |
| 35 | |
| 36 | template<class F> |
| 37 | struct is_callable_wrapper_fallback |
| 38 | { |
| 39 | template<class... Ts> |
| 40 | auto operator()(Ts&&...) const |
| 41 | -> decltype(std::declval<F>()(std::declval<Ts>()...)); |
| 42 | }; |
| 43 | |
| 44 | template<class T, class U=typename std::remove_cv<typename std::remove_reference<T>::type>::type> |
| 45 | struct is_callable_wrapper_base |
| 46 | : std::conditional<BOOST_HOF_IS_CLASS(U) && !BOOST_HOF_IS_FINAL(U), U, is_callable_wrapper_fallback<U>> |
| 47 | {}; |
| 48 | |
| 49 | template<class F, class... Ts> |
| 50 | struct is_callable_wrapper : is_callable_wrapper_base<F>::type |
| 51 | { |
| 52 | is_callable_wrapper(); |
| 53 | typedef cant_be_called_type const &(*pointer_to_function)(typename never_care<Ts>::type...); |
| 54 | operator pointer_to_function() const; |
| 55 | }; |
| 56 | |
| 57 | template<class T> |
| 58 | struct not_ |
| 59 | : std::integral_constant<bool, !T::value> |
| 60 | {}; |
| 61 | |
| 62 | template<class F, class... Ts> |
| 63 | struct can_be_called |
| 64 | : not_<std::is_same<cant_be_called_type, typename std::decay<decltype( |
| 65 | is_callable_wrapper<F, Ts...>()(std::declval<Ts>()...) |
| 66 | )>::type>> |
| 67 | {}; |
| 68 | |
| 69 | template<class F, class... Ts> |
| 70 | struct check_args; |
| 71 | |
| 72 | template<class Res, class... Ts, class... Us> |
| 73 | struct check_args<Res(Us...), Ts...> |
| 74 | : and_<std::is_convertible<Ts, Us>...> |
| 75 | {}; |
| 76 | |
| 77 | template<class Res, class... Ts, class... Us> |
| 78 | struct can_be_called<Res(*)(Us...), Ts...> |
| 79 | : std::conditional<sizeof...(Ts) == sizeof...(Us), |
| 80 | check_args<Res(Us...), Ts...>, |
| 81 | std::false_type |
| 82 | >::type |
| 83 | {}; |
| 84 | |
| 85 | template<class Res, class... Ts, class... Us> |
| 86 | struct can_be_called<Res(Us...), Ts...> |
| 87 | : std::conditional<sizeof...(Ts) == sizeof...(Us), |
| 88 | check_args<Res(Us...), Ts...>, |
| 89 | std::false_type |
| 90 | >::type |
| 91 | {}; |
| 92 | |
| 93 | #else |
| 94 | |
| 95 | template<class T> |
| 96 | T&& called_val() noexcept; |
| 97 | |
| 98 | template<class... Ts> |
| 99 | struct callable_args |
| 100 | {}; |
| 101 | |
| 102 | template<class F, class Args, class=void> |
| 103 | struct can_be_called_impl |
| 104 | : std::false_type |
| 105 | {}; |
| 106 | |
| 107 | template<class F, class... Args> |
| 108 | struct can_be_called_impl<F, callable_args<Args...>, typename detail::holder< |
| 109 | decltype( boost::hof::detail::called_val<F>()(boost::hof::detail::called_val<Args>()...) ) |
| 110 | >::type> |
| 111 | : std::true_type |
| 112 | {}; |
| 113 | |
| 114 | template<class F, class... Ts> |
| 115 | BOOST_HOF_USING(can_be_called, can_be_called_impl<F, detail::callable_args<Ts...>>); |
| 116 | |
| 117 | #endif |
| 118 | |
| 119 | }}} // namespace boost::hof |
| 120 | |
| 121 | #endif |
| 122 | |