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 78namespace boost { namespace hof { 79 80// TODO: Get rid of sequence parameter 81// Forward declare partial_adaptor, since it will be used below 82template<class F, class Pack=void > 83struct partial_adaptor; 84 85BOOST_HOF_DECLARE_STATIC_VAR(partial, detail::make<partial_adaptor>); 86 87namespace detail { 88 89template<class Derived, class F, class Pack> 90struct partial_adaptor_invoke 91{ 92 template<class... Ts> 93 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> 99 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 132template<class Derived, class F, class Pack> 133struct partial_adaptor_join 134{ 135 template<class... Ts> 136 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> 142 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 167template<class Derived, class F> 168struct partial_adaptor_pack 169{ 170 171 constexpr partial_adaptor_pack() noexcept 172 {} 173 174 template<class... Ts> 175 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}; 199template<class F, class Pack> 200struct 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 209template<class Derived, class F> 210struct 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 221template<class F, class Pack> 222struct 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> 229 constexpr const F& base_function(Ts&&...) const noexcept 230 { 231 return *this; 232 } 233 234 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> 244 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 250template<class F> 251struct 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> 258 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 270template<class F> 271struct 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 280template<class F> 281struct 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