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