invoke.h (5152B)
1 // Copyright 2020 The Chromium Authors 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 BASE_FUNCTIONAL_INVOKE_H_ 6 #define BASE_FUNCTIONAL_INVOKE_H_ 7 8 #include <type_traits> 9 #include <utility> 10 11 namespace base { 12 13 namespace internal { 14 15 // Helper struct and alias to deduce the class type from a member function 16 // pointer or member object pointer. 17 template <typename DecayedF> 18 struct member_pointer_class {}; 19 20 template <typename ReturnT, typename ClassT> 21 struct member_pointer_class<ReturnT ClassT::*> { 22 using type = ClassT; 23 }; 24 25 template <typename DecayedF> 26 using member_pointer_class_t = typename member_pointer_class<DecayedF>::type; 27 28 // Utility struct to detect specializations of std::reference_wrapper. 29 template <typename T> 30 struct is_reference_wrapper : std::false_type {}; 31 32 template <typename T> 33 struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; 34 35 // Small helpers used below in internal::invoke to make the SFINAE more concise. 36 template <typename F> 37 const bool& IsMemFunPtr = std::is_member_function_pointer_v<std::decay_t<F>>; 38 39 template <typename F> 40 const bool& IsMemObjPtr = std::is_member_object_pointer_v<std::decay_t<F>>; 41 42 template <typename F, 43 typename T, 44 typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>> 45 const bool& IsMemPtrToBaseOf = std::is_base_of_v<MemPtrClass, std::decay_t<T>>; 46 47 template <typename T> 48 const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value; 49 50 template <bool B> 51 using EnableIf = std::enable_if_t<B, bool>; 52 53 // Invokes a member function pointer on a reference to an object of a suitable 54 // type. Covers bullet 1 of the INVOKE definition. 55 // 56 // Reference: https://wg21.link/func.require#1.1 57 template <typename F, 58 typename T1, 59 typename... Args, 60 EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true> 61 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) { 62 return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...); 63 } 64 65 // Invokes a member function pointer on a std::reference_wrapper to an object of 66 // a suitable type. Covers bullet 2 of the INVOKE definition. 67 // 68 // Reference: https://wg21.link/func.require#1.2 69 template <typename F, 70 typename T1, 71 typename... Args, 72 EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true> 73 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) { 74 return (t1.get().*f)(std::forward<Args>(args)...); 75 } 76 77 // Invokes a member function pointer on a pointer-like type to an object of a 78 // suitable type. Covers bullet 3 of the INVOKE definition. 79 // 80 // Reference: https://wg21.link/func.require#1.3 81 template <typename F, 82 typename T1, 83 typename... Args, 84 EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> && 85 !IsRefWrapper<T1>> = true> 86 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) { 87 return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...); 88 } 89 90 // Invokes a member object pointer on a reference to an object of a suitable 91 // type. Covers bullet 4 of the INVOKE definition. 92 // 93 // Reference: https://wg21.link/func.require#1.4 94 template <typename F, 95 typename T1, 96 EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true> 97 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) { 98 return std::forward<T1>(t1).*f; 99 } 100 101 // Invokes a member object pointer on a std::reference_wrapper to an object of 102 // a suitable type. Covers bullet 5 of the INVOKE definition. 103 // 104 // Reference: https://wg21.link/func.require#1.5 105 template <typename F, 106 typename T1, 107 EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true> 108 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) { 109 return t1.get().*f; 110 } 111 112 // Invokes a member object pointer on a pointer-like type to an object of a 113 // suitable type. Covers bullet 6 of the INVOKE definition. 114 // 115 // Reference: https://wg21.link/func.require#1.6 116 template <typename F, 117 typename T1, 118 EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> && 119 !IsRefWrapper<T1>> = true> 120 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) { 121 return (*std::forward<T1>(t1)).*f; 122 } 123 124 // Invokes a regular function or function object. Covers bullet 7 of the INVOKE 125 // definition. 126 // 127 // Reference: https://wg21.link/func.require#1.7 128 template <typename F, typename... Args> 129 constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) { 130 return std::forward<F>(f)(std::forward<Args>(args)...); 131 } 132 133 } // namespace internal 134 135 // Implementation of C++17's std::invoke. This is not based on implementation 136 // referenced in original std::invoke proposal, but rather a manual 137 // implementation, so that it can be constexpr. 138 // 139 // References: 140 // - https://wg21.link/n4169#implementability 141 // - https://en.cppreference.com/w/cpp/utility/functional/invoke 142 // - https://wg21.link/func.invoke 143 template <typename F, typename... Args> 144 constexpr decltype(auto) invoke(F&& f, Args&&... args) { 145 return internal::InvokeImpl(std::forward<F>(f), std::forward<Args>(args)...); 146 } 147 148 } // namespace base 149 150 #endif // BASE_FUNCTIONAL_INVOKE_H_