#ifndef BOOST_PROTO17_EXPRESSION_HPP_INCLUDED #define BOOST_PROTO17_EXPRESSION_HPP_INCLUDED #include "expression_fwd.hpp" #include "detail/expression.hpp" #include #include #include namespace boost::proto17 { namespace adl_detail { template constexpr decltype(auto) eval_expression_as (E const & expr, hana::basic_type, Tuple && args) { return static_cast(detail::default_eval_expr(expr, static_cast(args))); } template constexpr decltype(auto) eval_expression_as (E const & expr, hana::basic_type, Tuple && args) { return detail::default_eval_expr(expr, static_cast(args)); } struct eval_expression_as_fn { template constexpr decltype(auto) operator() (E const & expr, hana::basic_type rtype, Tuple && args) const { return eval_expression_as(expr, rtype, static_cast(args)); } }; } using adl_detail::eval_expression_as_fn; inline namespace function_objects { inline constexpr eval_expression_as_fn eval_expression_as{}; } // TODO: static assert/SFINAE sizeof...(T) >= highest-indexed placeholder + 1 template decltype(auto) evaluate (Expr const & expr, T && ...t) { return detail::default_eval_expr(expr, hana::make_tuple(static_cast(t)...)); } // TODO: static assert/SFINAE sizeof...(T) >= highest-indexed placeholder + 1 template decltype(auto) evaluate_as (Expr const & expr, T && ...t) { return eval_expression_as(expr, hana::basic_type{}, hana::make_tuple(static_cast(t)...)); } template struct expression { using this_type = expression; using tuple_type = hana::tuple; static const expr_kind kind = Kind; expression (T && ... t) : elements (static_cast(t)...) {} expression (hana::tuple const & rhs) : elements (rhs) {} expression (hana::tuple && rhs) : elements (std::move(rhs)) {} expression & operator= (hana::tuple const & rhs) { elements = rhs.elements; } expression & operator= (hana::tuple && rhs) { elements = std::move(rhs.elements); } tuple_type elements; template operator R () { return eval_expression_as(*this, hana::basic_type{}, hana::tuple<>{}); } decltype(auto) value () const { using namespace hana::literals; static_assert( decltype(hana::size(elements))::value == 1UL, "value() is only defined for unary expressions." ); return elements[0_c]; } decltype(auto) left () const { using namespace hana::literals; static_assert( decltype(hana::size(elements))::value == 2UL, "left() and right() are only defined for binary expressions." ); return elements[0_c]; } decltype(auto) right () const { using namespace hana::literals; static_assert( decltype(hana::size(elements))::value == 2UL, "left() and right() are only defined for binary expressions." ); return elements[1_c]; } #define BOOST_PROTO17_UNARY_MEMBER_OPERATOR(op, op_name) \ decltype(auto) operator op const & \ { \ return expression{ \ hana::tuple{*this} \ }; \ } \ decltype(auto) operator op && \ { \ return expression{ \ hana::tuple{std::move(*this)} \ }; \ } BOOST_PROTO17_UNARY_MEMBER_OPERATOR(+(), unary_plus) // + BOOST_PROTO17_UNARY_MEMBER_OPERATOR(-(), negate) // - BOOST_PROTO17_UNARY_MEMBER_OPERATOR(*(), dereference) // * BOOST_PROTO17_UNARY_MEMBER_OPERATOR(~(), complement) // ~ BOOST_PROTO17_UNARY_MEMBER_OPERATOR(&(), address_of) // & BOOST_PROTO17_UNARY_MEMBER_OPERATOR(!(), logical_not) // ! BOOST_PROTO17_UNARY_MEMBER_OPERATOR(++(), pre_inc) // ++ BOOST_PROTO17_UNARY_MEMBER_OPERATOR(--(), pre_dec) // -- BOOST_PROTO17_UNARY_MEMBER_OPERATOR(++(int), post_inc) // ++(int) BOOST_PROTO17_UNARY_MEMBER_OPERATOR(--(int), post_dec) // --(int) #undef BOOST_PROTO17_UNARY_MEMBER_OPERATOR #define BOOST_PROTO17_BINARY_MEMBER_OPERATOR(op, op_name) \ template \ decltype(auto) operator op (U && rhs) const & \ { \ using rhs_type = typename detail::rhs_type::type; \ return expression{ \ hana::tuple{ \ *this, \ static_cast(rhs) \ } \ }; \ } \ template \ decltype(auto) operator op (U && rhs) && \ { \ using rhs_type = typename detail::rhs_type::type; \ return expression{ \ hana::tuple{ \ std::move(*this), \ static_cast(rhs) \ } \ }; \ } BOOST_PROTO17_BINARY_MEMBER_OPERATOR(<<, shift_left) // << BOOST_PROTO17_BINARY_MEMBER_OPERATOR(>>, shift_right) // >> BOOST_PROTO17_BINARY_MEMBER_OPERATOR(*, multiplies) // * BOOST_PROTO17_BINARY_MEMBER_OPERATOR(/, divides) // / BOOST_PROTO17_BINARY_MEMBER_OPERATOR(%, modulus) // % BOOST_PROTO17_BINARY_MEMBER_OPERATOR(+, plus) // + BOOST_PROTO17_BINARY_MEMBER_OPERATOR(-, minus) // - BOOST_PROTO17_BINARY_MEMBER_OPERATOR(<, less) // < BOOST_PROTO17_BINARY_MEMBER_OPERATOR(>, greater) // > BOOST_PROTO17_BINARY_MEMBER_OPERATOR(<=, less_equal) // <= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(>=, greater_equal) // >= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(==, equal_to) // == BOOST_PROTO17_BINARY_MEMBER_OPERATOR(!=, not_equal_to) // != BOOST_PROTO17_BINARY_MEMBER_OPERATOR(||, logical_or) // || BOOST_PROTO17_BINARY_MEMBER_OPERATOR(&&, logical_and) // && BOOST_PROTO17_BINARY_MEMBER_OPERATOR(&, bitwise_and) // & BOOST_PROTO17_BINARY_MEMBER_OPERATOR(|, bitwise_or) // | BOOST_PROTO17_BINARY_MEMBER_OPERATOR(^, bitwise_xor) // ^ template decltype(auto) operator, (U && rhs) const & { using rhs_type = typename detail::rhs_type::type; return expression{ hana::tuple{*this, static_cast(rhs)} }; } template decltype(auto) operator, (U && rhs) && { using rhs_type = typename detail::rhs_type::type; return expression{ hana::tuple{std::move(*this), static_cast(rhs)} }; } BOOST_PROTO17_BINARY_MEMBER_OPERATOR(->*, mem_ptr) // ->* BOOST_PROTO17_BINARY_MEMBER_OPERATOR(=, assign) // = BOOST_PROTO17_BINARY_MEMBER_OPERATOR(<<=, shift_left_assign) // <<= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(>>=, shift_right_assign) // >>= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(*=, multiplies_assign) // *= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(/=, divides_assign) // /= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(%=, modulus_assign) // %= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(+=, plus_assign) // += BOOST_PROTO17_BINARY_MEMBER_OPERATOR(-=, minus_assign) // -= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(&=, bitwise_and_assign) // &= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(|=, bitwise_or_assign) // |= BOOST_PROTO17_BINARY_MEMBER_OPERATOR(^=, bitwise_xor_assign) // ^= BOOST_PROTO17_BINARY_MEMBER_OPERATOR([], subscript) // [] template decltype(auto) operator() (U && ...u) const & { using tuple_type = hana::tuple::type...>; return detail::make_call_expression(*this, static_cast(u)...); } template decltype(auto) operator() (U && ...u) && { using tuple_type = hana::tuple::type...>; return detail::make_call_expression(std::move(*this), static_cast(u)...); } }; template auto make_terminal (T && t) { return expression{ hana::tuple{static_cast(t)} }; } } #include "detail/default_eval.hpp" #endif