]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*! |
2 | @file | |
3 | Defines `boost::hana::compose`. | |
4 | ||
5 | @copyright Louis Dionne 2013-2016 | |
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 | |
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 |