/*! @file Defines `boost::hana::lockstep`. @copyright Louis Dionne 2013-2017 Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_HANA_FUNCTIONAL_LOCKSTEP_HPP #define BOOST_HANA_FUNCTIONAL_LOCKSTEP_HPP #include #include #include #include #include BOOST_HANA_NAMESPACE_BEGIN //! @ingroup group-functional //! Invoke a function with the result of invoking other functions on its //! arguments, in lockstep. //! //! Specifically, `lockstep(f)(g1, ..., gN)` is a function such that //! @code //! lockstep(f)(g1, ..., gN)(x1, ..., xN) == f(g1(x1), ..., gN(xN)) //! @endcode //! //! Since each `g` is invoked on its corresponding argument in lockstep, //! the number of arguments must match the number of `g`s. //! //! //! Example //! ------- //! @include example/functional/lockstep.cpp #ifdef BOOST_HANA_DOXYGEN_INVOKED constexpr auto lockstep = [](auto&& f, auto&& ...g) { return [perfect-capture](auto&& ...x) -> decltype(auto) { return forwarded(f)(forwarded(g)(forwarded(x))...); }; }; #else template struct lockstep_t; template struct pre_lockstep_t; struct make_pre_lockstep_t { struct secret { }; template constexpr pre_lockstep_t::type> operator()(F&& f) const { return {static_cast(f)}; } }; template struct lockstep_t, F, G...> { template constexpr lockstep_t(make_pre_lockstep_t::secret, T&& ...t) : storage_{static_cast(t)...} { } basic_tuple storage_; template constexpr decltype(auto) operator()(X&& ...x) const& { return hana::at_c<0>(storage_)( hana::at_c(storage_)(static_cast(x))... ); } template constexpr decltype(auto) operator()(X&& ...x) & { return hana::at_c<0>(storage_)( hana::at_c(storage_)(static_cast(x))... ); } template constexpr decltype(auto) operator()(X&& ...x) && { return static_cast(hana::at_c<0>(storage_))( static_cast(hana::at_c(storage_))(static_cast(x))... ); } }; template struct pre_lockstep_t { F f; template constexpr lockstep_t, F, typename detail::decay::type...> operator()(G&& ...g) const& { return {make_pre_lockstep_t::secret{}, this->f, static_cast(g)...}; } template constexpr lockstep_t, F, typename detail::decay::type...> operator()(G&& ...g) && { return {make_pre_lockstep_t::secret{}, static_cast(this->f), static_cast(g)...}; } }; constexpr make_pre_lockstep_t lockstep{}; #endif BOOST_HANA_NAMESPACE_END #endif // !BOOST_HANA_FUNCTIONAL_LOCKSTEP_HPP