functional (4113B)
1 // -*- c++ -*- 2 #pragma once 3 4 #include <type_traits> 5 #include_next <functional> 6 7 namespace std 8 { 9 // based on http://en.cppreference.com/w/cpp/utility/functional/invoke 10 namespace detail 11 { 12 template <typename T> 13 struct is_reference_wrapper : false_type {}; 14 15 template <typename U> 16 struct is_reference_wrapper<reference_wrapper<U>> : true_type {}; 17 18 template <typename T> 19 constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value; 20 21 #define _DEF_INVOKE(check, ret) \ 22 template <typename T, typename Type, typename T1, typename... Args> \ 23 auto INVOKE(Type T::* f, T1&& t1, Args&&... args) \ 24 noexcept(noexcept(ret)) \ 25 -> enable_if_t< \ 26 is_member_function_pointer_v<decltype(f)> && check, \ 27 decltype(ret)> \ 28 { return ret; } 29 30 _DEF_INVOKE( 31 (is_base_of_v<T, decay_t<T1>>), 32 (std::forward<T1>(t1).*f)(std::forward<Args>(args)...)) 33 _DEF_INVOKE( 34 (!is_base_of_v<T, decay_t<T1>> && 35 is_reference_wrapper_v<decay_t<T1>>), 36 (t1.get().*f)(std::forward<Args>(args)...)) 37 _DEF_INVOKE( 38 (!is_base_of_v<T, decay_t<T1>> && 39 !is_reference_wrapper_v<decay_t<T1>>), 40 ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...)) 41 #undef _DEF_INVOKE 42 43 #define _DEF_INVOKE(check, ret) \ 44 template <typename T, typename Type, typename T1> \ 45 auto INVOKE(Type T::* f, T1&& t1) \ 46 noexcept(noexcept(ret)) \ 47 -> enable_if_t< \ 48 is_member_object_pointer_v<decltype(f)> && check, \ 49 decltype(ret)> \ 50 { return ret; } 51 52 _DEF_INVOKE( 53 (is_base_of_v<T, decay_t<T1>>), 54 std::forward<T1>(t1).*f) 55 _DEF_INVOKE( 56 (!is_base_of_v<T, decay_t<T1>> && 57 is_reference_wrapper_v<decay_t<T1>>), 58 t1.get().*f) 59 _DEF_INVOKE( 60 (!is_base_of_v<T, decay_t<T1>> && 61 !is_reference_wrapper_v<decay_t<T1>>), 62 (*std::forward<T1>(t1)).*f) 63 #undef _DEF_INVOKE 64 65 template <class F, class... Args> 66 auto INVOKE(F&& f, Args&&... args) 67 noexcept(noexcept(std::forward<F>(f)(std::forward<Args>(args)...))) 68 -> enable_if_t< 69 !is_member_function_pointer_v<F>, 70 decltype(std::forward<F>(f)(std::forward<Args>(args)...))> 71 { 72 return std::forward<F>(f)(std::forward<Args>(args)...); 73 } 74 75 template <typename AlwaysVoid, typename F, typename... Args> 76 struct invoke_result 77 { 78 decltype(void(INVOKE(declval<F>(), declval<Args>()...)))* x; 79 }; 80 template <typename F, typename... Args> 81 struct invoke_result< 82 decltype(void(INVOKE(declval<F>(), declval<Args>()...))), 83 F, Args...> 84 { 85 using type = decltype(INVOKE(declval<F>(), declval<Args>()...)); 86 }; 87 88 template <bool AlwaysTrue, typename F, typename... Args> 89 struct is_nothrow_invocable : false_type {}; 90 91 template <typename F, typename... Args> 92 struct is_nothrow_invocable< 93 noexcept(INVOKE(declval<F>(), declval<Args>()...)), 94 F, Args...> : true_type {}; 95 } 96 97 98 template <typename F, typename... ArgTypes> 99 struct invoke_result : detail::invoke_result<void, F, ArgTypes...> {}; 100 101 template <typename F, typename... ArgTypes> 102 using invoke_result_t = typename invoke_result<F, ArgTypes...>::type; 103 104 template <typename F, typename... ArgTypes> 105 struct is_nothrow_invocable 106 : detail::is_nothrow_invocable<true, F, ArgTypes...> {}; 107 108 template <typename F, typename... ArgTypes> 109 inline constexpr bool is_nothrow_invocable_v = 110 is_nothrow_invocable<F, ArgTypes...>::value; 111 112 template <typename F, typename... Args> 113 invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) 114 noexcept(is_nothrow_invocable_v<F, Args...>) 115 { 116 return detail::INVOKE(std::forward<F>(f), std::forward<Args>(args)...); 117 } 118 }