#include #include template struct future_expr { using this_type = future_expr; static boost::yap::expr_kind const kind = Kind; future_expr (Tuple && tuple) : elements (std::forward(tuple)) {} Tuple elements; auto get () const; BOOST_YAP_USER_BINARY_OPERATOR_MEMBER(logical_or, this_type, ::future_expr) BOOST_YAP_USER_BINARY_OPERATOR_MEMBER(logical_and, this_type, ::future_expr) }; template struct future : future_expr> { future (T const & t = T()) : future_expr> (boost::hana::tuple{t}) {} T get () const { return boost::yap::value(*this); } }; template using remove_cv_ref_t = std::remove_cv_t>; struct future_transform { template auto operator() ( future_expr< boost::yap::expr_kind::terminal, boost::hana::tuple > const & term ) { return term.elements; } template auto operator() ( future_expr< boost::yap::expr_kind::logical_or, boost::hana::tuple > const & or_expr ) { static_assert( std::is_same< decltype(boost::yap::value(boost::yap::left(or_expr))), decltype(boost::yap::value(boost::yap::right(or_expr))) >{} ); return boost::yap::transform(boost::yap::left(or_expr), *this); } template auto operator() ( future_expr< boost::yap::expr_kind::logical_and, boost::hana::tuple > const & and_expr ) { return boost::hana::concat( boost::yap::transform(boost::yap::left(and_expr), *this), boost::yap::transform(boost::yap::right(and_expr), *this) ); } }; template auto future_expr::get () const { return boost::yap::transform(*this, future_transform{}); } // TEST CASES struct A {}; struct B {}; struct C {}; template using vector = boost::hana::tuple; int main() { future a; future b; future c; future > ab; // Verify that various future groups have the // correct return types. A t0 = a.get(); vector t1 = (a && b && c).get(); vector t2 = ((a || a) && c).get(); vector t3 = ((a && b || a && b) && c).get(); vector, C> t4 = ((ab || ab) && c).get(); return 0; }