compose.hpp 3.3 KB

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