1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
// Copyright (C) 2016-2018 T. Zachary Laine
//
// 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)
//[ future_group
#include <boost/yap/algorithm.hpp>
#include <boost/hana/concat.hpp>
// A custom expression template for future groups. It supports operators ||
// and &&.
template <boost::yap::expr_kind Kind, typename Tuple>
struct future_expr
{
static boost::yap::expr_kind const kind = Kind;
future_expr (Tuple && tuple) :
elements (std::forward<Tuple &&>(tuple))
{}
Tuple elements;
// Returns the transformed/flattened expression.
auto get () const;
};
BOOST_YAP_USER_BINARY_OPERATOR(logical_or, future_expr, future_expr)
BOOST_YAP_USER_BINARY_OPERATOR(logical_and, future_expr, future_expr)
// A special-cased future terminal that matches the semantics from the
// original Proto example.
template <typename T>
struct future :
future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>>
{
future (T const & t = T()) :
future_expr<boost::yap::expr_kind::terminal, boost::hana::tuple<T>> (boost::hana::tuple<T>{t})
{}
T get () const
{ return boost::yap::value(*this); }
};
template <typename T>
using remove_cv_ref_t = std::remove_cv_t<std::remove_reference_t<T>>;
// A transform that flattens future expressions into a tuple.
struct future_transform
{
// Transform a terminal into its contained tuple.
template <typename T>
auto operator() (
future_expr<
boost::yap::expr_kind::terminal,
boost::hana::tuple<T>
> const & term
) {
return term.elements;
}
//[ expr_xform
// Transform left || right -> transform(left).
template <typename T, typename U>
auto operator() (
future_expr<
boost::yap::expr_kind::logical_or,
boost::hana::tuple<T, U>
> const & or_expr
) {
// Recursively transform the left side, and return the result.
// Without the recursion, we might return a terminal expression here
// insead of a tuple.
return boost::yap::transform(boost::yap::left(or_expr), *this);
}
//]
// Transform left && right -> concat(transform(left), transform(right)).
template <typename T, typename U>
auto operator() (
future_expr<
boost::yap::expr_kind::logical_and,
boost::hana::tuple<T, U>
> const & and_expr
) {
// Recursively transform each side, then combine the resulting tuples
// into a single tuple result.
return boost::hana::concat(
boost::yap::transform(boost::yap::left(and_expr), *this),
boost::yap::transform(boost::yap::right(and_expr), *this)
);
}
};
template <boost::yap::expr_kind Kind, typename Tuple>
auto future_expr<Kind, Tuple>::get () const
{ return boost::yap::transform(*this, future_transform{}); }
// TEST CASES
struct A {};
struct B {};
struct C {};
// Called "vector" just so the code in main() will match the original Proto
// example.
template <typename ...T>
using vector = boost::hana::tuple<T...>;
int main()
{
future<A> a;
future<B> b;
future<C> c;
future<vector<A,B> > ab;
// Verify that various future groups have the
// correct return types.
A t0 = a.get();
vector<A, B, C> t1 = (a && b && c).get();
vector<A, C> t2 = ((a || a) && c).get();
vector<A, B, C> t3 = ((a && b || a && b) && c).get();
vector<vector<A, B>, C> t4 = ((ab || ab) && c).get();
return 0;
}
//]
|