• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 =
38     std::is_member_function_pointer<std::decay_t<F>>::value;
39 
40 template <typename F>
41 const bool& IsMemObjPtr = std::is_member_object_pointer<std::decay_t<F>>::value;
42 
43 template <typename F,
44           typename T,
45           typename MemPtrClass = member_pointer_class_t<std::decay_t<F>>>
46 const bool& IsMemPtrToBaseOf =
47     std::is_base_of<MemPtrClass, std::decay_t<T>>::value;
48 
49 template <typename T>
50 const bool& IsRefWrapper = is_reference_wrapper<std::decay_t<T>>::value;
51 
52 template <bool B>
53 using EnableIf = std::enable_if_t<B, bool>;
54 
55 // Invokes a member function pointer on a reference to an object of a suitable
56 // type. Covers bullet 1 of the INVOKE definition.
57 //
58 // Reference: https://wg21.link/func.require#1.1
59 template <typename F,
60           typename T1,
61           typename... Args,
62           EnableIf<IsMemFunPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
63 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
64   return (std::forward<T1>(t1).*f)(std::forward<Args>(args)...);
65 }
66 
67 // Invokes a member function pointer on a std::reference_wrapper to an object of
68 // a suitable type. Covers bullet 2 of the INVOKE definition.
69 //
70 // Reference: https://wg21.link/func.require#1.2
71 template <typename F,
72           typename T1,
73           typename... Args,
74           EnableIf<IsMemFunPtr<F> && IsRefWrapper<T1>> = true>
75 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
76   return (t1.get().*f)(std::forward<Args>(args)...);
77 }
78 
79 // Invokes a member function pointer on a pointer-like type to an object of a
80 // suitable type. Covers bullet 3 of the INVOKE definition.
81 //
82 // Reference: https://wg21.link/func.require#1.3
83 template <typename F,
84           typename T1,
85           typename... Args,
86           EnableIf<IsMemFunPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
87                    !IsRefWrapper<T1>> = true>
88 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1, Args&&... args) {
89   return ((*std::forward<T1>(t1)).*f)(std::forward<Args>(args)...);
90 }
91 
92 // Invokes a member object pointer on a reference to an object of a suitable
93 // type. Covers bullet 4 of the INVOKE definition.
94 //
95 // Reference: https://wg21.link/func.require#1.4
96 template <typename F,
97           typename T1,
98           EnableIf<IsMemObjPtr<F> && IsMemPtrToBaseOf<F, T1>> = true>
99 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
100   return std::forward<T1>(t1).*f;
101 }
102 
103 // Invokes a member object pointer on a std::reference_wrapper to an object of
104 // a suitable type. Covers bullet 5 of the INVOKE definition.
105 //
106 // Reference: https://wg21.link/func.require#1.5
107 template <typename F,
108           typename T1,
109           EnableIf<IsMemObjPtr<F> && IsRefWrapper<T1>> = true>
110 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
111   return t1.get().*f;
112 }
113 
114 // Invokes a member object pointer on a pointer-like type to an object of a
115 // suitable type. Covers bullet 6 of the INVOKE definition.
116 //
117 // Reference: https://wg21.link/func.require#1.6
118 template <typename F,
119           typename T1,
120           EnableIf<IsMemObjPtr<F> && !IsMemPtrToBaseOf<F, T1> &&
121                    !IsRefWrapper<T1>> = true>
122 constexpr decltype(auto) InvokeImpl(F&& f, T1&& t1) {
123   return (*std::forward<T1>(t1)).*f;
124 }
125 
126 // Invokes a regular function or function object. Covers bullet 7 of the INVOKE
127 // definition.
128 //
129 // Reference: https://wg21.link/func.require#1.7
130 template <typename F, typename... Args>
131 constexpr decltype(auto) InvokeImpl(F&& f, Args&&... args) {
132   return std::forward<F>(f)(std::forward<Args>(args)...);
133 }
134 
135 }  // namespace internal
136 
137 // Implementation of C++17's std::invoke. This is not based on implementation
138 // referenced in original std::invoke proposal, but rather a manual
139 // implementation, so that it can be constexpr.
140 //
141 // References:
142 // - https://wg21.link/n4169#implementability
143 // - https://en.cppreference.com/w/cpp/utility/functional/invoke
144 // - https://wg21.link/func.invoke
145 template <typename F, typename... Args>
146 constexpr decltype(auto) invoke(F&& f, Args&&... args) {
147   return internal::InvokeImpl(std::forward<F>(f), std::forward<Args>(args)...);
148 }
149 
150 }  // namespace base
151 
152 #endif  // BASE_FUNCTIONAL_INVOKE_H_
153