/*============================================================================= Copyright (c) 2012 Paul Fultz II partial.h Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ==============================================================================*/ #ifndef BOOST_HOF_GUARD_FUNCTION_PARTIAL_H #define BOOST_HOF_GUARD_FUNCTION_PARTIAL_H /// partial /// ======== /// /// Description /// ----------- /// /// The `partial` function adaptor allows partial application of the function. /// If the function can not be called with all the parameters, it will return /// another function. It will repeatedly do this until the function can /// finally be called. By default, `partial` captures all of its variables by /// value, just like bind. As such all parameters must be `MoveConstructible` /// when the function is aprtial application. `std::ref` can be used to /// capture references instead. /// /// Synopsis /// -------- /// /// template /// constexpr partial_adaptor partial(F f); /// /// Semantics /// --------- /// /// assert(partial(f)(xs...)(ys...) == f(xs..., ys...)); /// /// Requirements /// ------------ /// /// F must be: /// /// * [ConstInvocable](ConstInvocable) /// * MoveConstructible /// /// Example /// ------- /// /// #include /// #include /// using namespace boost::hof; /// /// struct sum /// { /// template /// T operator()(T x, U y) const /// { /// return x+y; /// } /// }; /// /// int main() { /// assert(3 == partial(sum())(1)(2)); /// } /// /// References /// ---------- /// /// * [Partial application](https://en.wikipedia.org/wiki/Partial_application) /// * [Currying](https://en.wikipedia.org/wiki/Currying) /// #include #include #include #include #include namespace boost { namespace hof { // TODO: Get rid of sequence parameter // Forward declare partial_adaptor, since it will be used below template struct partial_adaptor; BOOST_HOF_DECLARE_STATIC_VAR(partial, detail::make); namespace detail { template struct partial_adaptor_invoke { template constexpr const F& get_function(Ts&&...) const noexcept { return static_cast(static_cast(*this)); } template constexpr const Pack& get_pack(Ts&&...) const noexcept { return static_cast(static_cast(*this)); } BOOST_HOF_RETURNS_CLASS(partial_adaptor_invoke); template constexpr BOOST_HOF_SFINAE_RESULT ( typename result_of, result_of...> >::type, id_ ) operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS ( boost::hof::pack_join ( BOOST_HOF_MANGLE_CAST(const Pack&)(BOOST_HOF_CONST_THIS->get_pack(xs...)), boost::hof::pack_forward(BOOST_HOF_FORWARD(Ts)(xs)...) ) (BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...))) ); }; #ifdef _MSC_VER #define BOOST_HOF_PARTIAL_RETURNS(...) -> decltype(__VA_ARGS__) { return (__VA_ARGS__); } #else #define BOOST_HOF_PARTIAL_RETURNS BOOST_HOF_SFINAE_RETURNS #endif template struct partial_adaptor_join { template constexpr const F& get_function(Ts&&...) const noexcept { return static_cast(static_cast(*this)); } template constexpr const Pack& get_pack(Ts&&...) const noexcept { return static_cast(static_cast(*this)); } BOOST_HOF_RETURNS_CLASS(partial_adaptor_join); template::value) >::type> constexpr auto operator()(Ts&&... xs) const #ifdef _MSC_VER // Workaround ICE on MSVC noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, F&&) && noexcept(boost::hof::pack_join(std::declval(), boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...)))) #endif BOOST_HOF_PARTIAL_RETURNS ( boost::hof::partial ( BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...)), 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)...)) ) ); }; template struct partial_adaptor_pack { constexpr partial_adaptor_pack() noexcept {} template constexpr const F& get_function(Ts&&...) const noexcept { return static_cast(static_cast(*this)); } BOOST_HOF_RETURNS_CLASS(partial_adaptor_pack); template::value) >::type> constexpr auto operator()(Ts&&... xs) const #ifdef _MSC_VER // Workaround ICE on MSVC noexcept(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, F&&) && noexcept(boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...))) #endif BOOST_HOF_PARTIAL_RETURNS ( boost::hof::partial ( BOOST_HOF_RETURNS_C_CAST(F&&)(BOOST_HOF_CONST_THIS->get_function(xs...)), boost::hof::pack(BOOST_HOF_FORWARD(Ts)(xs)...) ) ); }; template struct partial_adaptor_base { typedef basic_first_of_adaptor < partial_adaptor_invoke, F, Pack>, partial_adaptor_join, F, Pack> > type; }; template struct partial_adaptor_pack_base { typedef basic_first_of_adaptor < F, partial_adaptor_pack > type; }; } template struct partial_adaptor : detail::partial_adaptor_base::type, F, Pack { typedef typename detail::partial_adaptor_base::type base; typedef partial_adaptor fit_rewritable1_tag; template constexpr const F& base_function(Ts&&...) const noexcept { return *this; } constexpr const Pack& get_pack() const noexcept { return *this; } using base::operator(); BOOST_HOF_INHERIT_DEFAULT(partial_adaptor, base, F, Pack); template constexpr partial_adaptor(X&& x, S&& seq) BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(F, X&&) && BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(Pack, S&&)) : F(BOOST_HOF_FORWARD(X)(x)), Pack(BOOST_HOF_FORWARD(S)(seq)) {} }; template struct partial_adaptor : detail::partial_adaptor_pack_base, detail::callable_base>::type { typedef typename detail::partial_adaptor_pack_base, detail::callable_base>::type base; typedef partial_adaptor fit_rewritable1_tag; template constexpr const detail::callable_base& base_function(Ts&&...) const noexcept { return *this; } using base::operator(); BOOST_HOF_INHERIT_CONSTRUCTOR(partial_adaptor, base); }; // Make partial_adaptor work with pipable_adaptor by removing its pipableness template struct partial_adaptor, void> : partial_adaptor { typedef partial_adaptor base; typedef partial_adaptor fit_rewritable1_tag; BOOST_HOF_INHERIT_CONSTRUCTOR(partial_adaptor, base); }; template struct partial_adaptor>, void> : partial_adaptor { typedef partial_adaptor base; typedef partial_adaptor fit_rewritable1_tag; BOOST_HOF_INHERIT_CONSTRUCTOR(partial_adaptor, base); }; }} // namespace boost::hof #endif