• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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