1 /*============================================================================= 2 Copyright (c) 2015 Paul Fultz II 3 apply.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_APPLY_H 9 #define BOOST_HOF_GUARD_APPLY_H 10 11 /// apply 12 /// ===== 13 /// 14 /// Description 15 /// ----------- 16 /// 17 /// The `apply` function calls the function given to it with its arguments. 18 /// 19 /// Synopsis 20 /// -------- 21 /// 22 /// template<class F, class... Ts> 23 /// constexpr auto apply(F&& f, Ts&&... xs); 24 /// 25 /// Semantics 26 /// --------- 27 /// 28 /// assert(apply(f)(xs...) == f(xs...)); 29 /// assert(fold(apply, f)(x, y, z) == f(x)(y)(z)); 30 /// 31 /// Requirements 32 /// ------------ 33 /// 34 /// F must be: 35 /// 36 /// * [Invocable](Invocable) 37 /// 38 /// Example 39 /// ------- 40 /// 41 /// #include <boost/hof.hpp> 42 /// #include <cassert> 43 /// 44 /// struct sum_f 45 /// { 46 /// template<class T, class U> 47 /// T operator()(T x, U y) const 48 /// { 49 /// return x+y; 50 /// } 51 /// }; 52 /// 53 /// int main() { 54 /// assert(boost::hof::apply(sum_f(), 1, 2) == 3); 55 /// } 56 /// 57 58 #include <boost/hof/detail/result_of.hpp> 59 #include <boost/hof/detail/forward.hpp> 60 #include <boost/hof/detail/static_const_var.hpp> 61 62 #ifdef _MSC_VER 63 #pragma warning(push) 64 #pragma warning(disable: 4003) 65 #endif 66 67 #define BOOST_HOF_DETAIL_FOREACH_QUAL(m, data) \ 68 m(, data) \ 69 m(const, data) \ 70 m(volatile, data) \ 71 m(const volatile, data) 72 73 namespace boost { namespace hof { 74 75 namespace detail { 76 #if BOOST_HOF_HAS_MANUAL_DEDUCTION || BOOST_HOF_NO_EXPRESSION_SFINAE 77 struct apply_mem_fn 78 { 79 template<class...> 80 struct convertible_args; 81 82 template<class T, class U, class=void> 83 struct is_convertible_args 84 : std::false_type 85 {}; 86 87 template<class... Ts, class... Us> 88 struct is_convertible_args< 89 convertible_args<Ts...>, 90 convertible_args<Us...>, 91 typename std::enable_if<( 92 sizeof...(Ts) == sizeof...(Us) 93 )>::type 94 > 95 : and_<std::is_convertible<Ts, Us>...> 96 {}; 97 98 template<class From, class To> 99 struct is_compatible 100 : std::is_convertible< 101 typename std::add_pointer<typename std::remove_reference<From>::type>::type, 102 typename std::add_pointer<typename std::remove_reference<To>::type>::type 103 > 104 {}; 105 106 #define BOOST_HOF_APPLY_MEM_FN_CALL(cv, data) \ 107 template <class R, class Base, class Derived, class... Ts, class... Us, class=typename std::enable_if<and_< \ 108 is_compatible<Derived, cv Base>, \ 109 is_convertible_args<convertible_args<Us...>, convertible_args<Ts...>> \ 110 >::value>::type> \ 111 constexpr R operator()(R (Base::*mf)(Ts...) cv, Derived&& ref, Us &&... xs) const \ 112 BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT((BOOST_HOF_FORWARD(Derived)(ref).*mf)(BOOST_HOF_FORWARD(Us)(xs)...)) \ 113 { \ 114 return (BOOST_HOF_FORWARD(Derived)(ref).*mf)(BOOST_HOF_FORWARD(Us)(xs)...); \ 115 } 116 BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_FN_CALL, ~) 117 }; 118 119 struct apply_mem_data 120 { 121 template<class T, class R> 122 struct match_qualifier 123 { typedef R type; }; 124 125 #define BOOST_HOF_APPLY_MEM_DATA_MATCH(cv, ref) \ 126 template<class T, class R> \ 127 struct match_qualifier<cv T ref, R> \ 128 : match_qualifier<T, cv R ref> \ 129 {}; 130 131 BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_DATA_MATCH,&) 132 BOOST_HOF_DETAIL_FOREACH_QUAL(BOOST_HOF_APPLY_MEM_DATA_MATCH,&&) 133 134 template <class Base, class R, class Derived, class=typename std::enable_if<( 135 std::is_base_of<Base, typename std::decay<Derived>::type>::value 136 )>::type> 137 constexpr typename match_qualifier<Derived, R>::type operator ()boost::hof::detail::apply_mem_data138 operator()(R Base::*pmd, Derived&& ref) const noexcept 139 { 140 return BOOST_HOF_FORWARD(Derived)(ref).*pmd; 141 } 142 }; 143 144 template<class T, class U=decltype(*std::declval<T>())> 145 struct apply_deref 146 { typedef U type; }; 147 148 #endif 149 150 struct apply_f 151 { 152 #if BOOST_HOF_HAS_MANUAL_DEDUCTION || BOOST_HOF_NO_EXPRESSION_SFINAE 153 template<class F, class T, class... Ts, class=typename std::enable_if<( 154 std::is_member_function_pointer<typename std::decay<F>::type>::value 155 )>::type> 156 constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<T>, id_<Ts>...) 157 operator()(F&& f, T&& obj, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS 158 ( 159 apply_mem_fn()(f, BOOST_HOF_FORWARD(T)(obj), BOOST_HOF_FORWARD(Ts)(xs)...) 160 ); 161 162 template<class F, class T, class... Ts, class U=typename apply_deref<T>::type, class=typename std::enable_if<( 163 std::is_member_function_pointer<typename std::decay<F>::type>::value 164 )>::type> 165 constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<U>, id_<Ts>...) 166 operator()(F&& f, T&& obj, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS 167 ( 168 apply_mem_fn()(f, *BOOST_HOF_FORWARD(T)(obj), BOOST_HOF_FORWARD(Ts)(xs)...) 169 ); 170 171 template<class F, class T, class... Ts, class=typename std::enable_if<( 172 std::is_member_function_pointer<typename std::decay<F>::type>::value 173 )>::type> 174 constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<T&>, id_<Ts>...) 175 operator()(F&& f, const std::reference_wrapper<T>& ref, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS 176 ( 177 apply_mem_fn()(f, ref.get(), BOOST_HOF_FORWARD(Ts)(xs)...) 178 ); 179 180 template<class F, class T, class=typename std::enable_if<( 181 std::is_member_object_pointer<typename std::decay<F>::type>::value 182 )>::type> 183 constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<T>) 184 operator()(F&& f, T&& obj) const BOOST_HOF_SFINAE_MANUAL_RETURNS 185 ( 186 apply_mem_data()(f, BOOST_HOF_FORWARD(T)(obj)) 187 ); 188 189 template<class F, class T, class U=typename apply_deref<T>::type, class=typename std::enable_if<( 190 std::is_member_object_pointer<typename std::decay<F>::type>::value 191 )>::type> 192 constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<U>) 193 operator()(F&& f, T&& obj) const BOOST_HOF_SFINAE_MANUAL_RETURNS 194 ( 195 apply_mem_data()(f, *BOOST_HOF_FORWARD(T)(obj)) 196 ); 197 198 template<class F, class T, class=typename std::enable_if<( 199 std::is_member_object_pointer<typename std::decay<F>::type>::value 200 )>::type> 201 constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<T&>) 202 operator()(F&& f, const std::reference_wrapper<T>& ref) const BOOST_HOF_SFINAE_MANUAL_RETURNS 203 ( 204 apply_mem_data()(f, ref.get()) 205 ); 206 207 #else 208 209 template <class Base, class T, class Derived> 210 constexpr auto operator()(T Base::*pmd, Derived&& ref) const 211 BOOST_HOF_RETURNS(BOOST_HOF_FORWARD(Derived)(ref).*pmd); 212 213 template <class PMD, class Pointer> 214 constexpr auto operator()(PMD&& pmd, Pointer&& ptr) const 215 BOOST_HOF_RETURNS((*BOOST_HOF_FORWARD(Pointer)(ptr)).*BOOST_HOF_FORWARD(PMD)(pmd)); 216 217 template <class Base, class T, class Derived> 218 constexpr auto operator()(T Base::*pmd, const std::reference_wrapper<Derived>& ref) const 219 BOOST_HOF_RETURNS(ref.get().*pmd); 220 221 template <class Base, class T, class Derived, class... Args> 222 constexpr auto operator()(T Base::*pmf, Derived&& ref, Args&&... args) const 223 BOOST_HOF_RETURNS((BOOST_HOF_FORWARD(Derived)(ref).*pmf)(BOOST_HOF_FORWARD(Args)(args)...)); 224 225 template <class PMF, class Pointer, class... Args> 226 constexpr auto operator()(PMF&& pmf, Pointer&& ptr, Args&&... args) const 227 BOOST_HOF_RETURNS(((*BOOST_HOF_FORWARD(Pointer)(ptr)).*BOOST_HOF_FORWARD(PMF)(pmf))(BOOST_HOF_FORWARD(Args)(args)...)); 228 229 template <class Base, class T, class Derived, class... Args> 230 constexpr auto operator()(T Base::*pmf, const std::reference_wrapper<Derived>& ref, Args&&... args) const 231 BOOST_HOF_RETURNS((ref.get().*pmf)(BOOST_HOF_FORWARD(Args)(args)...)); 232 233 #endif 234 template<class F, class... Ts> 235 constexpr BOOST_HOF_SFINAE_MANUAL_RESULT(F, id_<Ts>...) 236 operator()(F&& f, Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS 237 ( 238 f(BOOST_HOF_FORWARD(Ts)(xs)...) 239 ); 240 }; 241 242 } 243 244 BOOST_HOF_DECLARE_STATIC_VAR(apply, detail::apply_f); 245 246 }} // namespace boost::hof 247 248 #ifdef _MSC_VER 249 #pragma warning(pop) 250 #endif 251 252 #endif 253