lockstep.hpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*!
  2. @file
  3. Defines `boost::hana::lockstep`.
  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_LOCKSTEP_HPP
  9. #define BOOST_HANA_FUNCTIONAL_LOCKSTEP_HPP
  10. #include <boost/hana/basic_tuple.hpp>
  11. #include <boost/hana/config.hpp>
  12. #include <boost/hana/detail/decay.hpp>
  13. #include <cstddef>
  14. #include <utility>
  15. BOOST_HANA_NAMESPACE_BEGIN
  16. //! @ingroup group-functional
  17. //! Invoke a function with the result of invoking other functions on its
  18. //! arguments, in lockstep.
  19. //!
  20. //! Specifically, `lockstep(f)(g1, ..., gN)` is a function such that
  21. //! @code
  22. //! lockstep(f)(g1, ..., gN)(x1, ..., xN) == f(g1(x1), ..., gN(xN))
  23. //! @endcode
  24. //!
  25. //! Since each `g` is invoked on its corresponding argument in lockstep,
  26. //! the number of arguments must match the number of `g`s.
  27. //!
  28. //!
  29. //! Example
  30. //! -------
  31. //! @include example/functional/lockstep.cpp
  32. #ifdef BOOST_HANA_DOXYGEN_INVOKED
  33. constexpr auto lockstep = [](auto&& f, auto&& ...g) {
  34. return [perfect-capture](auto&& ...x) -> decltype(auto) {
  35. return forwarded(f)(forwarded(g)(forwarded(x))...);
  36. };
  37. };
  38. #else
  39. template <typename Indices, typename F, typename ...G>
  40. struct lockstep_t;
  41. template <typename F>
  42. struct pre_lockstep_t;
  43. struct make_pre_lockstep_t {
  44. struct secret { };
  45. template <typename F>
  46. constexpr pre_lockstep_t<typename detail::decay<F>::type> operator()(F&& f) const {
  47. return {static_cast<F&&>(f)};
  48. }
  49. };
  50. template <std::size_t ...n, typename F, typename ...G>
  51. struct lockstep_t<std::index_sequence<n...>, F, G...> {
  52. template <typename ...T>
  53. constexpr lockstep_t(make_pre_lockstep_t::secret, T&& ...t)
  54. : storage_{static_cast<T&&>(t)...}
  55. { }
  56. basic_tuple<F, G...> storage_;
  57. template <typename ...X>
  58. constexpr decltype(auto) operator()(X&& ...x) const& {
  59. return hana::at_c<0>(storage_)(
  60. hana::at_c<n+1>(storage_)(static_cast<X&&>(x))...
  61. );
  62. }
  63. template <typename ...X>
  64. constexpr decltype(auto) operator()(X&& ...x) & {
  65. return hana::at_c<0>(storage_)(
  66. hana::at_c<n+1>(storage_)(static_cast<X&&>(x))...
  67. );
  68. }
  69. template <typename ...X>
  70. constexpr decltype(auto) operator()(X&& ...x) && {
  71. return static_cast<F&&>(hana::at_c<0>(storage_))(
  72. static_cast<G&&>(hana::at_c<n+1>(storage_))(static_cast<X&&>(x))...
  73. );
  74. }
  75. };
  76. template <typename F>
  77. struct pre_lockstep_t {
  78. F f;
  79. template <typename ...G>
  80. constexpr lockstep_t<std::make_index_sequence<sizeof...(G)>, F,
  81. typename detail::decay<G>::type...>
  82. operator()(G&& ...g) const& {
  83. return {make_pre_lockstep_t::secret{}, this->f, static_cast<G&&>(g)...};
  84. }
  85. template <typename ...G>
  86. constexpr lockstep_t<std::make_index_sequence<sizeof...(G)>, F,
  87. typename detail::decay<G>::type...>
  88. operator()(G&& ...g) && {
  89. return {make_pre_lockstep_t::secret{}, static_cast<F&&>(this->f),
  90. static_cast<G&&>(g)...};
  91. }
  92. };
  93. constexpr make_pre_lockstep_t lockstep{};
  94. #endif
  95. BOOST_HANA_NAMESPACE_END
  96. #endif // !BOOST_HANA_FUNCTIONAL_LOCKSTEP_HPP