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 62namespace boost { namespace hof { namespace detail { 63 64template<class S, class F, class... Gs> 65struct combine_adaptor_base; 66 67template<std::size_t... Ns, class F, class... Gs> 68struct 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 73 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> 83 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 114template<class F, class... Gs> 115struct 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 122BOOST_HOF_DECLARE_STATIC_VAR(combine, detail::make<combine_adaptor>); 123 124}} // namespace boost::hof 125 126#endif 127