1 /*============================================================================= 2 Copyright (c) 2015 Paul Fultz II 3 combine.h 4 Distributed under the Boost Software License, Version 1.0. (See accompanying 5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 ==============================================================================*/ 7 8 #ifndef BOOST_HOF_GUARD_COMBINE_H 9 #define BOOST_HOF_GUARD_COMBINE_H 10 11 /// combine 12 /// ======= 13 /// 14 /// Description 15 /// ----------- 16 /// 17 /// The `combine` function adaptor combines several functions together with 18 /// their arguments. It essentially zips each function with an argument before 19 /// calling the main function. 20 /// 21 /// Synopsis 22 /// -------- 23 /// 24 /// template<class F, class... Gs> 25 /// constexpr combine_adaptor<F, Gs...> combine(F f, Gs... gs); 26 /// 27 /// Semantics 28 /// --------- 29 /// 30 /// assert(combine(f, gs...)(xs...) == f(gs(xs)...)); 31 /// 32 /// Requirements 33 /// ------------ 34 /// 35 /// F and Gs must be: 36 /// 37 /// * [ConstInvocable](ConstInvocable) 38 /// * MoveConstructible 39 /// 40 /// Example 41 /// ------- 42 /// 43 /// #include <boost/hof.hpp> 44 /// #include <cassert> 45 /// #include <tuple> 46 /// #include <utility> 47 /// 48 /// int main() { 49 /// auto f = boost::hof::combine( 50 /// boost::hof::construct<std::tuple>(), 51 /// boost::hof::capture(1)(boost::hof::construct<std::pair>()), 52 /// boost::hof::capture(2)(boost::hof::construct<std::pair>())); 53 /// assert(f(3, 7) == std::make_tuple(std::make_pair(1, 3), std::make_pair(2, 7))); 54 /// } 55 /// 56 57 #include <boost/hof/pack.hpp> 58 #include <boost/hof/always.hpp> 59 #include <boost/hof/detail/callable_base.hpp> 60 #include <boost/hof/detail/make.hpp> 61 62 namespace boost { namespace hof { namespace detail { 63 64 template<class S, class F, class... Gs> 65 struct combine_adaptor_base; 66 67 template<std::size_t... Ns, class F, class... Gs> 68 struct combine_adaptor_base<seq<Ns...>, F, Gs...> 69 : F, pack_base<seq<Ns...>, Gs...> 70 { 71 typedef pack_base<seq<Ns...>, Gs...> base_type; 72 BOOST_HOF_INHERIT_DEFAULTboost::hof::detail::combine_adaptor_base73 BOOST_HOF_INHERIT_DEFAULT(combine_adaptor_base, base_type, F) 74 75 template<class X, class... Xs, 76 BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(F, X), 77 BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(base_type, Xs...)> 78 constexpr combine_adaptor_base(X&& x, Xs&&... xs) 79 : F(BOOST_HOF_FORWARD(X)(x)), base_type(BOOST_HOF_FORWARD(Xs)(xs)...) 80 {} 81 82 template<class... Ts> base_functionboost::hof::detail::combine_adaptor_base83 constexpr const F& base_function(Ts&&... xs) const 84 { 85 return boost::hof::always_ref(*this)(xs...); 86 } 87 88 BOOST_HOF_RETURNS_CLASS(combine_adaptor_base); 89 90 // Result needs to be calculated in a separate class to avoid confusing the 91 // compiler on MSVC 92 #if BOOST_HOF_NO_EXPRESSION_SFINAE || BOOST_HOF_HAS_MANUAL_DEDUCTION 93 template<class... Ts> 94 struct combine_result 95 : result_of<const F&, result_of<const Gs&, id_<Ts>>...> 96 {}; 97 #endif 98 99 template<class... Ts> 100 #if BOOST_HOF_NO_EXPRESSION_SFINAE || BOOST_HOF_HAS_MANUAL_DEDUCTION 101 constexpr typename combine_result<Ts...>::type 102 #else 103 constexpr auto 104 #endif 105 operator()(Ts&&... xs) const BOOST_HOF_SFINAE_MANUAL_RETURNS 106 ( 107 (BOOST_HOF_MANGLE_CAST(const F&)(BOOST_HOF_CONST_THIS->base_function(xs...))) 108 (boost::hof::alias_value<pack_tag<seq<Ns>, Gs...>, Gs>(*BOOST_HOF_CONST_THIS, xs)(BOOST_HOF_FORWARD(Ts)(xs))...) 109 ); 110 }; 111 112 } 113 114 template<class F, class... Gs> 115 struct combine_adaptor 116 : detail::combine_adaptor_base<typename detail::gens<sizeof...(Gs)>::type, detail::callable_base<F>, detail::callable_base<Gs>...> 117 { 118 typedef detail::combine_adaptor_base<typename detail::gens<sizeof...(Gs)>::type, detail::callable_base<F>, detail::callable_base<Gs>...> base_type; 119 BOOST_HOF_INHERIT_CONSTRUCTOR(combine_adaptor, base_type) 120 }; 121 122 BOOST_HOF_DECLARE_STATIC_VAR(combine, detail::make<combine_adaptor>); 123 124 }} // namespace boost::hof 125 126 #endif 127