1 /*! 2 @file 3 Defines `boost::hana::compose`. 4 5 @copyright Louis Dionne 2013-2017 6 Distributed under the Boost Software License, Version 1.0. 7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 8 */ 9 10 #ifndef BOOST_HANA_FUNCTIONAL_COMPOSE_HPP 11 #define BOOST_HANA_FUNCTIONAL_COMPOSE_HPP 12 13 #include <boost/hana/config.hpp> 14 #include <boost/hana/detail/create.hpp> 15 #include <boost/hana/detail/variadic/foldl1.hpp> 16 17 #include <utility> 18 19 20 BOOST_HANA_NAMESPACE_BEGIN 21 //! @ingroup group-functional 22 //! Return the composition of two functions or more. 23 //! 24 //! `compose` is defined inductively. When given more than two functions, 25 //! `compose(f, g, h...)` is equivalent to `compose(f, compose(g, h...))`. 26 //! When given two functions, `compose(f, g)` is a function such that 27 //! @code 28 //! compose(f, g)(x, y...) == f(g(x), y...) 29 //! @endcode 30 //! 31 //! If you need composition of the form `f(g(x, y...))`, use `demux` instead. 32 //! 33 //! @note 34 //! `compose` is an associative operation; `compose(f, compose(g, h))` 35 //! is equivalent to `compose(compose(f, g), h)`. 36 //! 37 //! @internal 38 //! ### Proof of associativity 39 //! 40 //! @code 41 //! compose(f, compose(g, h))(x, xs...) == f(compose(g, h)(x), xs...) 42 //! == f(g(h(x)), xs...) 43 //! 44 //! compose(compose(f, g), h)(x, xs...) == compose(f, g)(h(x), xs...) 45 //! == f(g(h(x)), xs...) 46 //! @endcode 47 //! @endinternal 48 //! 49 //! ### Example 50 //! @include example/functional/compose.cpp 51 #ifdef BOOST_HANA_DOXYGEN_INVOKED __anon7afbd2840102(auto&& f1, auto&& f2, ..., auto&& fn) 52 constexpr auto compose = [](auto&& f1, auto&& f2, ..., auto&& fn) { 53 return [perfect-capture](auto&& x, auto&& ...xs) -> decltype(auto) { 54 return forwarded(f1)( 55 forwarded(f2)( 56 ... 57 forwarded(fn)(forwarded(x)) 58 ), 59 forwarded(xs)... 60 ); 61 } 62 }; 63 #else 64 template <typename F, typename G> 65 struct _compose { 66 F f; G g; 67 68 template <typename X, typename ...Xs> 69 constexpr decltype(auto) operator()(X&& x, Xs&& ...xs) const& { 70 return f( 71 g(static_cast<X&&>(x)), 72 static_cast<Xs&&>(xs)... 73 ); 74 } 75 76 template <typename X, typename ...Xs> 77 constexpr decltype(auto) operator()(X&& x, Xs&& ...xs) & { 78 return f( 79 g(static_cast<X&&>(x)), 80 static_cast<Xs&&>(xs)... 81 ); 82 } 83 84 template <typename X, typename ...Xs> 85 constexpr decltype(auto) operator()(X&& x, Xs&& ...xs) && { 86 return std::move(f)( 87 std::move(g)(static_cast<X&&>(x)), 88 static_cast<Xs&&>(xs)... 89 ); 90 } 91 }; 92 93 struct _make_compose { 94 template <typename F, typename G, typename ...H> 95 constexpr decltype(auto) operator()(F&& f, G&& g, H&& ...h) const { 96 return detail::variadic::foldl1(detail::create<_compose>{}, 97 static_cast<F&&>(f), 98 static_cast<G&&>(g), 99 static_cast<H&&>(h)... 100 ); 101 } 102 }; 103 104 constexpr _make_compose compose{}; 105 #endif 106 BOOST_HANA_NAMESPACE_END 107 108 #endif // !BOOST_HANA_FUNCTIONAL_COMPOSE_HPP 109