/*============================================================================= Copyright (c) 2014 Paul Fultz II proj.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_ON_H #define BOOST_HOF_GUARD_FUNCTION_ON_H /// proj /// ==== /// /// Description /// ----------- /// /// The `proj` function adaptor applies a projection onto the parameters of /// another function. This is useful, for example, to define a function for /// sorting such that the ordering is based off of the value of one of its /// member fields. /// /// Also, if just a projection is given, then the projection will be called /// for each of its arguments. /// /// Note: All projections are always evaluated in order from left-to-right. /// /// Synopsis /// -------- /// /// template /// constexpr proj_adaptor proj(Projection p, F f); /// /// template /// constexpr proj_adaptor proj(Projection p); /// /// Semantics /// --------- /// /// assert(proj(p, f)(xs...) == f(p(xs)...)); /// assert(proj(p)(xs...) == p(xs)...); /// /// Requirements /// ------------ /// /// Projection must be: /// /// * [UnaryInvocable](UnaryInvocable) /// * MoveConstructible /// /// F must be: /// /// * [ConstInvocable](ConstInvocable) /// * MoveConstructible /// /// Example /// ------- /// /// #include /// #include /// using namespace boost::hof; /// /// struct foo /// { /// foo(int x_) : x(x_) /// {} /// int x; /// }; /// /// int main() { /// assert(boost::hof::proj(&foo::x, _ + _)(foo(1), foo(2)) == 3); /// } /// /// References /// ---------- /// /// * [Projections](Projections) /// * [Variadic print]() /// #include #include #include #include #include #include #include #include #include #include namespace boost { namespace hof { namespace detail { template struct project_eval { T&& x; const Projection& p; template constexpr project_eval(X&& xp, const P& pp) : x(BOOST_HOF_FORWARD(X)(xp)), p(pp) {} constexpr auto operator()() const BOOST_HOF_RETURNS (p(BOOST_HOF_FORWARD(T)(x))); }; template constexpr project_eval make_project_eval(T&& x, const Projection& p) { return project_eval(BOOST_HOF_FORWARD(T)(x), p); } template struct project_void_eval { T&& x; const Projection& p; template constexpr project_void_eval(X&& xp, const P& pp) : x(BOOST_HOF_FORWARD(X)(xp)), p(pp) {} struct void_ {}; constexpr void_ operator()() const { return p(BOOST_HOF_FORWARD(T)(x)), void_(); } }; template constexpr project_void_eval make_project_void_eval(T&& x, const Projection& p) { return project_void_eval(BOOST_HOF_FORWARD(T)(x), p); } template()(std::declval()(std::declval())...) )> constexpr R by_eval(const Projection& p, const F& f, Ts&&... xs) { return boost::hof::apply_eval(f, make_project_eval(BOOST_HOF_FORWARD(Ts)(xs), p)...); } #if BOOST_HOF_NO_ORDERED_BRACE_INIT #define BOOST_HOF_BY_VOID_RETURN BOOST_HOF_ALWAYS_VOID_RETURN #else #if BOOST_HOF_NO_CONSTEXPR_VOID #define BOOST_HOF_BY_VOID_RETURN boost::hof::detail::swallow #else #define BOOST_HOF_BY_VOID_RETURN void #endif #endif template constexpr BOOST_HOF_ALWAYS_VOID_RETURN by_void_eval(const Projection& p, Ts&&... xs) { return boost::hof::apply_eval(boost::hof::always(), boost::hof::detail::make_project_void_eval(BOOST_HOF_FORWARD(Ts)(xs), p)...); } struct swallow { template constexpr swallow(Ts&&...) {} }; } template struct proj_adaptor; template struct proj_adaptor : detail::compressed_pair, detail::callable_base>, detail::function_result_type { typedef proj_adaptor fit_rewritable_tag; typedef detail::compressed_pair, detail::callable_base> base; template constexpr const detail::callable_base& base_function(Ts&&... xs) const { return this->second(xs...);; } template constexpr const detail::callable_base& base_projection(Ts&&... xs) const { return this->first(xs...); } struct by_failure { template struct apply { template struct of : Failure::template of>()(std::declval()))...> {}; }; }; struct failure : failure_map> {}; BOOST_HOF_INHERIT_CONSTRUCTOR(proj_adaptor, base) BOOST_HOF_RETURNS_CLASS(proj_adaptor); template constexpr BOOST_HOF_SFINAE_RESULT(const detail::callable_base&, result_of&, id_>...) operator()(Ts&&... xs) const BOOST_HOF_SFINAE_RETURNS ( boost::hof::detail::by_eval( BOOST_HOF_MANGLE_CAST(const detail::callable_base&)(BOOST_HOF_CONST_THIS->base_projection(xs...)), BOOST_HOF_MANGLE_CAST(const detail::callable_base&)(BOOST_HOF_CONST_THIS->base_function(xs...)), BOOST_HOF_FORWARD(Ts)(xs)... ) ); }; template struct proj_adaptor : detail::callable_base { typedef proj_adaptor fit_rewritable1_tag; template constexpr const detail::callable_base& base_projection(Ts&&... xs) const { return boost::hof::always_ref(*this)(xs...); } BOOST_HOF_INHERIT_DEFAULT(proj_adaptor, detail::callable_base) template)> constexpr proj_adaptor(P&& p) : detail::callable_base(BOOST_HOF_FORWARD(P)(p)) {} BOOST_HOF_RETURNS_CLASS(proj_adaptor); template()(std::declval()))...>> constexpr BOOST_HOF_BY_VOID_RETURN operator()(Ts&&... xs) const { #if BOOST_HOF_NO_ORDERED_BRACE_INIT return boost::hof::detail::by_void_eval(this->base_projection(xs...), BOOST_HOF_FORWARD(Ts)(xs)...); #else #if BOOST_HOF_NO_CONSTEXPR_VOID return #endif boost::hof::detail::swallow{ (this->base_projection(xs...)(BOOST_HOF_FORWARD(Ts)(xs)), 0)... }; #endif } }; BOOST_HOF_DECLARE_STATIC_VAR(proj, detail::make); }} // namespace boost::hof #endif