/*============================================================================= Copyright (c) 2014 Paul Fultz II pack.h Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ==============================================================================*/ #ifndef BOOST_HOF_GUARD_FUNCTION_PACK_H #define BOOST_HOF_GUARD_FUNCTION_PACK_H /// pack /// ==== /// /// Description /// ----------- /// /// The `pack` function returns a higher order function object that takes a /// function that will be passed the initial elements. The function object is /// a sequence that can be unpacked with `unpack_adaptor` as well. Also, /// `pack_join` can be used to join multiple packs together. /// /// Synopsis /// -------- /// /// // Decay everything before capturing /// template /// constexpr auto pack(Ts&&... xs); /// /// // Capture lvalues by reference and rvalue reference by reference /// template /// constexpr auto pack_forward(Ts&&... xs); /// /// // Capture lvalues by reference and rvalues by value. /// template /// constexpr auto pack_basic(Ts&&... xs); /// /// // Join multiple packs together /// template /// constexpr auto pack_join(Ts&&... xs); /// /// Semantics /// --------- /// /// assert(pack(xs...)(f) == f(xs...)); /// assert(unpack(f)(pack(xs...)) == f(xs...)); /// /// assert(pack_join(pack(xs...), pack(ys...)) == pack(xs..., ys...)); /// /// /// Example /// ------- /// /// #include /// #include /// using namespace boost::hof; /// /// struct sum /// { /// template /// T operator()(T x, U y) const /// { /// return x+y; /// } /// }; /// /// int main() { /// int r = pack(3, 2)(sum()); /// assert(r == 5); /// } /// /// See Also /// -------- /// /// * [unpack](unpack) /// #include #include #include #include #include #include #include #include #include namespace boost { namespace hof { namespace detail { template struct pack_tag {}; template struct pack_holder : detail::alias_empty {}; template struct pack_base; template struct is_copyable : std::integral_constant {}; template struct is_copyable : std::true_type {}; template struct is_copyable : std::true_type {}; template::value && !std::is_lvalue_reference::value , int>::type = 0> constexpr T pack_get(X&& x, Ts&&... xs) noexcept(BOOST_HOF_IS_NOTHROW_COPY_CONSTRUCTIBLE(T)) { return static_cast(boost::hof::alias_value(BOOST_HOF_FORWARD(X)(x), xs...)); } template::value , int>::type = 0> constexpr T pack_get(X&& x, Ts&&... xs) noexcept { return boost::hof::alias_value(x, xs...); } template::value , int>::type = 0> constexpr auto pack_get(X&& x, Ts&&... xs) BOOST_HOF_RETURNS ( boost::hof::alias_value(BOOST_HOF_FORWARD(X)(x), xs...) ); #if (defined(__GNUC__) && !defined (__clang__) && __GNUC__ == 4 && __GNUC_MINOR__ < 7) || defined(_MSC_VER) template struct pack_holder_base : Ts::type... { template::type> constexpr pack_holder_base(Xs&&... xs) BOOST_HOF_NOEXCEPT(BOOST_HOF_AND_UNPACK(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(typename Ts::type, Xs&&))) : Ts::type(BOOST_HOF_FORWARD(Xs)(xs))... {} #ifndef _MSC_VER // BOOST_HOF_INHERIT_DEFAULT(pack_holder_base, typename std::remove_cv::type>::type...) BOOST_HOF_INHERIT_DEFAULT(pack_holder_base, typename Ts::type...) #endif }; template struct pack_holder_base : T::type { typedef typename T::type base; BOOST_HOF_INHERIT_CONSTRUCTOR(pack_holder_base, base); }; template struct pack_holder_builder { template struct apply : pack_holder, Ts...>> {}; }; template struct pack_base, Ts...> : pack_holder_base::template apply...> { typedef pack_holder_base::template apply...> base; template constexpr pack_base(X1&& x1, X2&& x2, Xs&&... xs) BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X1&&, X2&&, Xs&...)) : base(BOOST_HOF_FORWARD(X1)(x1), BOOST_HOF_FORWARD(X2)(x2), BOOST_HOF_FORWARD(Xs)(xs)...) {} template::type = 0> constexpr pack_base(X1&& x1) BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X1&&)) : base(BOOST_HOF_FORWARD(X1)(x1)) {} // BOOST_HOF_INHERIT_DEFAULT(pack_base, typename std::remove_cv::type>::type...); BOOST_HOF_INHERIT_DEFAULT(pack_base, Ts...); BOOST_HOF_RETURNS_CLASS(pack_base); template constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS ( f(boost::hof::detail::pack_get, Ts...>>(*BOOST_HOF_CONST_THIS, f)...) ); typedef std::integral_constant fit_function_param_limit; template struct apply : F::template apply {}; }; template struct pack_base, T> : pack_holder_base, T>>> { typedef pack_holder_base, T>>> base; template::type = 0> constexpr pack_base(X1&& x1) BOOST_HOF_NOEXCEPT(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(base, X1&&)) : base(BOOST_HOF_FORWARD(X1)(x1)) {} BOOST_HOF_INHERIT_DEFAULT(pack_base, T); BOOST_HOF_RETURNS_CLASS(pack_base); template constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS ( f(boost::hof::detail::pack_get, T>>(*BOOST_HOF_CONST_THIS, f)) ); typedef std::integral_constant fit_function_param_limit; template struct apply : F::template apply {}; }; #else template struct pack_base, Ts...> : pack_holder, Ts...>>::type... { // BOOST_HOF_INHERIT_DEFAULT(pack_base, typename std::remove_cv::type>::type...); BOOST_HOF_INHERIT_DEFAULT(pack_base, Ts...); template, Ts...>>::type)> constexpr pack_base(Xs&&... xs) BOOST_HOF_NOEXCEPT(BOOST_HOF_AND_UNPACK(BOOST_HOF_IS_NOTHROW_CONSTRUCTIBLE(typename pack_holder, Ts...>>::type, Xs&&))) : pack_holder, Ts...>>::type(BOOST_HOF_FORWARD(Xs)(xs))... {} // typedef pack_base, Ts...> self_t; BOOST_HOF_RETURNS_CLASS(pack_base); template constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS ( f(boost::hof::detail::pack_get, Ts...>>(*BOOST_HOF_CONST_THIS, f)...) ); typedef std::integral_constant fit_function_param_limit; template struct apply : F::template apply {}; }; #endif template<> struct pack_base > { template constexpr auto operator()(F&& f) const BOOST_HOF_RETURNS (f()); typedef std::integral_constant fit_function_param_limit; template struct apply : F::template apply<> {}; }; #define BOOST_HOF_DETAIL_UNPACK_PACK_BASE(ref, move) \ template \ constexpr auto unpack_pack_base(F&& f, pack_base, Ts...> ref x) \ BOOST_HOF_RETURNS(f(boost::hof::alias_value, Ts...>, Ts>(move(x), f)...)) BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_UNPACK_PACK_BASE) template struct pack_join_base; // TODO: Extend to join more than two packs at a time template struct pack_join_base, Ts1...>, pack_base, Ts2...>> { static constexpr long total_size = sizeof...(Ts1) + sizeof...(Ts2); typedef pack_base::type, Ts1..., Ts2...> result_type; template static constexpr result_type call(P1&& p1, P2&& p2) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT( result_type( boost::hof::detail::pack_get, Ts1...>>(BOOST_HOF_FORWARD(P1)(p1))..., boost::hof::detail::pack_get, Ts2...>>(BOOST_HOF_FORWARD(P2)(p2))...) ) { return result_type( boost::hof::detail::pack_get, Ts1...>>(BOOST_HOF_FORWARD(P1)(p1))..., boost::hof::detail::pack_get, Ts2...>>(BOOST_HOF_FORWARD(P2)(p2))...); } }; template struct pack_join_result : pack_join_base< typename std::remove_cv::type>::type, typename std::remove_cv::type>::type > {}; struct pack_basic_f { template constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS ( pack_base::type, typename remove_rvalue_reference::type...>(BOOST_HOF_FORWARD(Ts)(xs)...) ); }; struct pack_forward_f { template constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS ( pack_base::type, Ts&&...>(BOOST_HOF_FORWARD(Ts)(xs)...) ); }; struct pack_f { template constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS ( pack_basic_f()(boost::hof::decay(BOOST_HOF_FORWARD(Ts)(xs))...) ); }; template constexpr typename pack_join_result::result_type make_pack_join_dual(P1&& p1, P2&& p2) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(pack_join_result::call(BOOST_HOF_FORWARD(P1)(p1), BOOST_HOF_FORWARD(P2)(p2))) { return pack_join_result::call(BOOST_HOF_FORWARD(P1)(p1), BOOST_HOF_FORWARD(P2)(p2)); } // Manually compute join return type to make older gcc happy template struct join_type; template struct join_type { typedef T type; }; template struct join_type { typedef typename pack_join_result::type>::result_type type; }; template constexpr P1 make_pack_join(P1&& p1) BOOST_HOF_NOEXCEPT_CONSTRUCTIBLE(P1, P1&&) { return BOOST_HOF_FORWARD(P1)(p1); } template constexpr typename join_type::type make_pack_join(P1&& p1, Ps&&... ps) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(make_pack_join_dual(BOOST_HOF_FORWARD(P1)(p1), make_pack_join(BOOST_HOF_FORWARD(Ps)(ps)...))) { return make_pack_join_dual(BOOST_HOF_FORWARD(P1)(p1), make_pack_join(BOOST_HOF_FORWARD(Ps)(ps)...)); } struct pack_join_f { template constexpr auto operator()(Ps&&... ps) const BOOST_HOF_RETURNS ( make_pack_join(BOOST_HOF_FORWARD(Ps)(ps)...) ); }; } BOOST_HOF_DECLARE_STATIC_VAR(pack_basic, detail::pack_basic_f); BOOST_HOF_DECLARE_STATIC_VAR(pack_forward, detail::pack_forward_f); BOOST_HOF_DECLARE_STATIC_VAR(pack, detail::pack_f); BOOST_HOF_DECLARE_STATIC_VAR(pack_join, detail::pack_join_f); template struct unpack_sequence> { template constexpr static auto apply(F&& f, P&& p) BOOST_HOF_RETURNS ( boost::hof::detail::unpack_pack_base(BOOST_HOF_FORWARD(F)(f), BOOST_HOF_FORWARD(P)(p)) ); }; }} // namespace boost::hof #endif