1 // Copyright 2021 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_TYPE_TRAITS_H_ 6 #define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_TYPE_TRAITS_H_ 7 8 #include <type_traits> 9 10 namespace cpp17 { 11 namespace internal { 12 13 template <typename T> 14 static constexpr bool is_reference_wrapper = false; 15 template <typename T> 16 static constexpr bool is_reference_wrapper<std::reference_wrapper<T>> = true; 17 18 // These are from [func.require] ¶ 1.1-7 19 template <typename MemFn, typename Class, typename T> 20 static constexpr bool invoke_pmf_base = std::is_member_function_pointer<MemFn Class::*>::value&& 21 std::is_base_of<Class, std::remove_reference_t<T>>::value; 22 23 template <typename MemFn, typename Class, typename T> 24 static constexpr bool invoke_pmf_refwrap = std::is_member_function_pointer<MemFn Class::*>::value&& 25 is_reference_wrapper<std::remove_cv_t<std::remove_reference_t<T>>>; 26 27 template <typename MemFn, typename Class, typename T> 28 static constexpr bool invoke_pmf_other = 29 std::is_member_function_pointer<MemFn Class::*>::value && !invoke_pmf_base<MemFn, Class, T> && 30 !invoke_pmf_refwrap<MemFn, Class, T>; 31 32 template <typename MemObj, typename Class, typename T> 33 static constexpr bool invoke_pmd_base = std::is_member_object_pointer<MemObj Class::*>::value&& 34 std::is_base_of<Class, std::remove_reference_t<T>>::value; 35 36 template <typename MemObj, typename Class, typename T> 37 static constexpr bool invoke_pmd_refwrap = std::is_member_object_pointer<MemObj Class::*>::value&& 38 is_reference_wrapper<std::remove_cv_t<std::remove_reference_t<T>>>; 39 40 template <typename MemObj, typename Class, typename T> 41 static constexpr bool invoke_pmd_other = 42 std::is_member_object_pointer<MemObj Class::*>::value && !invoke_pmd_base<MemObj, Class, T> && 43 !invoke_pmd_refwrap<MemObj, Class, T>; 44 45 // ¶ 1.7 says to just return f(t1, t2, ..., tn) in all other cases 46 47 // Just internal forward declarations for SFINAE; cpp20::invoke is defined in 48 // lib/stdcompat/functional.h 49 template <typename MemFn, typename Class, typename T, typename... Args> 50 constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args) 51 -> std::enable_if_t<invoke_pmf_base<MemFn, Class, T>, 52 decltype((std::forward<T>(obj).*f)(std::forward<Args>(args)...))>; 53 54 template <typename MemFn, typename Class, typename T, typename... Args> 55 constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args) 56 -> std::enable_if_t<invoke_pmf_refwrap<MemFn, Class, T>, 57 decltype((obj.get().*f)(std::forward<Args>(args)...))>; 58 59 template <typename MemFn, typename Class, typename T, typename... Args> 60 constexpr auto invoke(MemFn Class::*f, T&& obj, Args&&... args) 61 -> std::enable_if_t<invoke_pmf_other<MemFn, Class, T>, 62 decltype(((*std::forward<T>(obj)).*f)(std::forward<Args>(args)...))>; 63 64 template <typename MemObj, typename Class, typename T> 65 constexpr auto invoke(MemObj Class::*f, T&& obj) 66 -> std::enable_if_t<invoke_pmd_base<MemObj, Class, T>, decltype(std::forward<T>(obj).*f)>; 67 68 template <typename MemObj, typename Class, typename T> 69 constexpr auto invoke(MemObj Class::*f, T&& obj) 70 -> std::enable_if_t<invoke_pmd_refwrap<MemObj, Class, T>, decltype(obj.get().*f)>; 71 72 template <typename MemObj, typename Class, typename T> 73 constexpr auto invoke(MemObj Class::*f, T&& obj) 74 -> std::enable_if_t<invoke_pmd_other<MemObj, Class, T>, decltype((*std::forward<T>(obj)).*f)>; 75 76 template <typename F, typename... Args> 77 constexpr auto invoke(F&& f, Args&&... args) 78 -> decltype(std::forward<F>(f)(std::forward<Args>(args)...)); 79 80 template <typename R, typename F, typename... Args, 81 typename = std::enable_if_t<std::is_void<R>::value>> 82 constexpr auto invoke_r(F&& f, Args&&... args) 83 -> decltype(static_cast<void>(::cpp17::internal::invoke(std::forward<F>(f), 84 std::forward<Args>(args)...))); 85 86 template <typename R, typename F, typename... Args, 87 typename = std::enable_if_t<!std::is_void<R>::value>> 88 constexpr auto invoke_r(F&& f, Args&&... args) 89 -> std::enable_if_t<std::is_convertible<decltype(::cpp17::internal::invoke( 90 std::forward<F>(f), std::forward<Args>(args)...)), 91 R>::value, 92 R>; 93 94 template <typename R, typename F, typename... Args> 95 constexpr auto is_valid_invoke(std::nullptr_t) 96 -> decltype(invoke_r<R>(std::declval<F>(), std::declval<Args>()...), std::true_type()); 97 98 template <typename R, typename F, typename... Args> 99 constexpr std::false_type is_valid_invoke(...); 100 101 template <bool Enable, typename F, typename... Args> 102 struct invoke_result {}; 103 104 template <typename F, typename... Args> 105 struct invoke_result<true, F, Args...> { 106 using type = decltype(::cpp17::internal::invoke(std::declval<F>(), std::declval<Args>()...)); 107 }; 108 109 } // namespace internal 110 } // namespace cpp17 111 112 #endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_INTERNAL_TYPE_TRAITS_H_ 113