1 /*============================================================================= 2 Copyright (c) 2012 Paul Fultz II 3 partial.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_FUNCTION_PARTIAL_H 9 #define BOOST_HOF_GUARD_FUNCTION_PARTIAL_H 10 11 /// partial 12 /// ======== 13 /// 14 /// Description 15 /// ----------- 16 /// 17 /// The `partial` function adaptor allows partial application of the function. 18 /// If the function can not be called with all the parameters, it will return 19 /// another function. It will repeatedly do this until the function can 20 /// finally be called. By default, `partial` captures all of its variables by 21 /// value, just like bind. As such all parameters must be `MoveConstructible` 22 /// when the function is aprtial application. `std::ref` can be used to 23 /// capture references instead. 24 /// 25 /// Synopsis 26 /// -------- 27 /// 28 /// template<class F> 29 /// constexpr partial_adaptor<F> partial(F f); 30 /// 31 /// Semantics 32 /// --------- 33 /// 34 /// assert(partial(f)(xs...)(ys...) == f(xs..., ys...)); 35 /// 36 /// Requirements 37 /// ------------ 38 /// 39 /// F must be: 40 /// 41 /// * [ConstInvocable](ConstInvocable) 42 /// * MoveConstructible 43 /// 44 /// Example 45 /// ------- 46 /// 47 /// #include <boost/hof.hpp> 48 /// #include <cassert> 49 /// using namespace boost::hof; 50 /// 51 /// struct sum 52 /// { 53 /// template<class T, class U> 54 /// T operator()(T x, U y) const 55 /// { 56 /// return x+y; 57 /// } 58 /// }; 59 /// 60 /// int main() { 61 /// assert(3 == partial(sum())(1)(2)); 62 /// } 63 /// 64 /// References 65 /// ---------- 66 /// 67 /// * [Partial application](https://en.wikipedia.org/wiki/Partial_application) 68 /// * [Currying](https://en.wikipedia.org/wiki/Currying) 69 /// 70 71 #include <boost/hof/first_of.hpp> 72 #include <boost/hof/static.hpp> 73 #include <boost/hof/pipable.hpp> 74 #include <boost/hof/detail/make.hpp> 75 #include <boost/hof/detail/static_const_var.hpp> 76 77 78 namespace boost { namespace hof { 79 80 // TODO: Get rid of sequence parameter 81 // Forward declare partial_adaptor, since it will be used below 82 template<class F, class Pack=void > 83 struct partial_adaptor; 84 85 BOOST_HOF_DECLARE_STATIC_VAR(partial, detail::make<partial_adaptor>); 86 87 namespace detail { 88 89 template<class Derived, class F, class Pack> 90 struct partial_adaptor_invoke 91 { 92 template<class... Ts> get_functionboost::hof::detail::partial_adaptor_invoke93 constexpr const F& get_function(Ts&&...) const noexcept 94 { 95 return static_cast<const F&>(static_cast<const Derived&>(*this)); 96 } 97 98 template<class... Ts> get_packboost::hof::detail::partial_adaptor_invoke99 constexpr const Pack& get_pack(Ts&&...) const noexcept 100 { 101 return static_cast<const Pack&>(static_cast<const Derived&>(*this)); 102 } 103 104 BOOST_HOF_RETURNS_CLASS(partial_adaptor_invoke); 105 106 template<class... Ts> 107 constexpr BOOST_HOF_SFINAE_RESULT 108 ( 109 typename result_of<decltype(boost::hof::pack_join), 110 id_<const Pack&>, 111 result_of<decltype(boost::hof::pack_forward), id_<Ts>...> 112 >::type, 113 id_<F&&> 114 ) 115 operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS 116 ( 117 boost::hof::pack_join 118 ( 119 BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...)), 120 boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...) 121 ) 122 (BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...))) 123 ); 124 }; 125 126 #ifdef _MSC_VER 127 #define BOOST_HOF_PARTIAL_RETURNS(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); } 128 #else 129 #define BOOST_HOF_PARTIAL_RETURNS BOOST_HOF_SFINAE_RETURNS 130 #endif 131 132 template<class Derived, class F, class Pack> 133 struct partial_adaptor_join 134 { 135 template<class... Ts> get_functionboost::hof::detail::partial_adaptor_join136 constexpr const F& get_function(Ts&&...) const noexcept 137 { 138 return static_cast<const F&>(static_cast<const Derived&>(*this)); 139 } 140 141 template<class... Ts> get_packboost::hof::detail::partial_adaptor_join142 constexpr const Pack& get_pack(Ts&&...) const noexcept 143 { 144 return static_cast<const Pack&>(static_cast<const Derived&>(*this)); 145 } 146 147 BOOST_HOF_RETURNS_CLASS(partial_adaptor_join); 148 149 template<class... Ts, class=typename std::enable_if< 150 ((sizeof...(Ts) + Pack::fit_function_param_limit::value) < function_param_limit<F>::value) 151 >::type> 152 constexpr auto operator()(Ts&&... xs) const 153 #ifdef _MSC_VER 154 // Workaround ICE on MSVC 155 noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, F&&) && noexcept(boost::hof::pack_join(std::declval<const Pack&>(), boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...)))) 156 #endif 157 BOOST_HOF_PARTIAL_RETURNS 158 ( 159 boost::hof::partial 160 ( 161 BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...)), 162 boost::hof::pack_join(BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...)), boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...)) 163 ) 164 ); 165 }; 166 167 template<class Derived, class F> 168 struct partial_adaptor_pack 169 { 170 partial_adaptor_packboost::hof::detail::partial_adaptor_pack171 constexpr partial_adaptor_pack() noexcept 172 {} 173 174 template<class... Ts> get_functionboost::hof::detail::partial_adaptor_pack175 constexpr const F& get_function(Ts&&...) const noexcept 176 { 177 return static_cast<const F&>(static_cast<const Derived&>(*this)); 178 } 179 180 BOOST_HOF_RETURNS_CLASS(partial_adaptor_pack); 181 182 template<class... Ts, class=typename std::enable_if< 183 (sizeof...(Ts) < function_param_limit<F>::value) 184 >::type> 185 constexpr auto operator()(Ts&&... xs) const 186 #ifdef _MSC_VER 187 // Workaround ICE on MSVC 188 noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, F&&) && noexcept(boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...))) 189 #endif 190 BOOST_HOF_PARTIAL_RETURNS 191 ( 192 boost::hof::partial 193 ( 194 BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...)), 195 boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...) 196 ) 197 ); 198 }; 199 template<class F, class Pack> 200 struct partial_adaptor_base 201 { 202 typedef basic_first_of_adaptor 203 < 204 partial_adaptor_invoke<partial_adaptor<F, Pack>, F, Pack>, 205 partial_adaptor_join<partial_adaptor<F, Pack>, F, Pack> 206 > type; 207 }; 208 209 template<class Derived, class F> 210 struct partial_adaptor_pack_base 211 { 212 typedef basic_first_of_adaptor 213 < 214 F, 215 partial_adaptor_pack<Derived, F> 216 > type; 217 }; 218 219 } 220 221 template<class F, class Pack> 222 struct partial_adaptor : detail::partial_adaptor_base<F, Pack>::type, F, Pack 223 { 224 typedef typename detail::partial_adaptor_base<F, Pack>::type base; 225 226 typedef partial_adaptor fit_rewritable1_tag; 227 228 template<class... Ts> base_functionboost::hof::partial_adaptor229 constexpr const F& base_function(Ts&&...) const noexcept 230 { 231 return *this; 232 } 233 get_packboost::hof::partial_adaptor234 constexpr const Pack& get_pack() const noexcept 235 { 236 return *this; 237 } 238 239 using base::operator(); 240 241 BOOST_HOF_INHERIT_DEFAULT(partial_adaptor, base, F, Pack); 242 243 template<class X, class S> partial_adaptorboost::hof::partial_adaptor244 constexpr partial_adaptor(X&& x, S&& seq) 245 BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, X&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(Pack, S&&)) 246 : F(BOOST_HOF_FORWARD(X)(x)), Pack(BOOST_HOF_FORWARD(S)(seq)) 247 {} 248 }; 249 250 template<class F> 251 struct partial_adaptor<F, void> : detail::partial_adaptor_pack_base<partial_adaptor<F, void>, detail::callable_base<F>>::type 252 { 253 typedef typename detail::partial_adaptor_pack_base<partial_adaptor<F, void>, detail::callable_base<F>>::type base; 254 255 typedef partial_adaptor fit_rewritable1_tag; 256 257 template<class... Ts> base_functionboost::hof::partial_adaptor258 constexpr const detail::callable_base<F>& base_function(Ts&&...) const noexcept 259 { 260 return *this; 261 } 262 263 using base::operator(); 264 265 BOOST_HOF_INHERIT_CONSTRUCTOR(partial_adaptor, base); 266 267 }; 268 269 // Make partial_adaptor work with pipable_adaptor by removing its pipableness 270 template<class F> 271 struct partial_adaptor<pipable_adaptor<F>, void> 272 : partial_adaptor<F, void> 273 { 274 typedef partial_adaptor<F, void> base; 275 276 typedef partial_adaptor fit_rewritable1_tag; 277 BOOST_HOF_INHERIT_CONSTRUCTOR(partial_adaptor, base); 278 }; 279 280 template<class F> 281 struct partial_adaptor<static_<pipable_adaptor<F>>, void> 282 : partial_adaptor<F, void> 283 { 284 typedef partial_adaptor<F, void> base; 285 286 typedef partial_adaptor fit_rewritable1_tag; 287 288 BOOST_HOF_INHERIT_CONSTRUCTOR(partial_adaptor, base); 289 }; 290 }} // namespace boost::hof 291 292 #endif 293