#ifndef BOOST_PP_IS_ITERATING /////////////////////////////////////////////////////////////////////////////// /// \file default.hpp /// Definintion of default_context, a default evaluation context for /// proto::eval() that uses Boost.Typeof to deduce return types /// of the built-in operators. // // Copyright 2007 Eric Niebler. 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_PROTO_CONTEXT_DEFAULT_HPP_EAN_01_08_2007 #define BOOST_PROTO_CONTEXT_DEFAULT_HPP_EAN_01_08_2007 #include // must be first include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for proto::arg_c() #include // must be last include // If we're generating doxygen documentation, hide all the nasty // Boost.Typeof gunk. #ifndef BOOST_PROTO_DOXYGEN_INVOKED #define BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_(Nested, Expr)\ BOOST_TYPEOF_NESTED_TYPEDEF_TPL(BOOST_PP_CAT(nested_and_hidden_, Nested), Expr)\ static int const sz = sizeof(detail::check_reference(Expr)); \ struct Nested\ : mpl::if_c<\ 1==sz\ , typename BOOST_PP_CAT(nested_and_hidden_, Nested)::type &\ , typename BOOST_PP_CAT(nested_and_hidden_, Nested)::type\ >\ {}; #define BOOST_PROTO_DECLTYPE_(Expr, Type)\ BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_(BOOST_PP_CAT(nested_, Type), (Expr))\ typedef typename BOOST_PP_CAT(nested_, Type)::type Type; #else /// INTERNAL ONLY /// #define BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_(Nested, Expr) /// INTERNAL ONLY /// #define BOOST_PROTO_DECLTYPE_(Expr, Type)\ typedef detail::unspecified Type; #endif namespace boost { namespace proto { namespace detail { template T make(); template char check_reference(T &); template char (&check_reference(T const &))[2]; template struct comma_result { BOOST_PROTO_DECLTYPE_((detail::make(), detail::make()), type) }; template struct comma_result { typedef void type; }; template struct comma_result { typedef A1 type; }; template<> struct comma_result { typedef void type; }; template struct result_of_fixup : mpl::if_, T *, U> {}; template struct result_of_fixup : result_of_fixup {}; template struct result_of_fixup : result_of_fixup {}; template struct result_of_fixup : result_of_fixup {}; //// Tests for result_of_fixup //struct bar {}; //BOOST_MPL_ASSERT((is_same::type>)); //BOOST_MPL_ASSERT((is_same::type>)); //BOOST_MPL_ASSERT((is_same::type>)); //BOOST_MPL_ASSERT((is_same::type>)); //BOOST_MPL_ASSERT((is_same::type>)); //BOOST_MPL_ASSERT((is_same::type>)); //BOOST_MPL_ASSERT((is_same::type>)); //BOOST_MPL_ASSERT((is_same::type>)); #if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) template T &make_ref_(T &t); template T const &make_ref_(T const &t); #define BOOST_PROTO_REF(x) detail::make_ref_(x) #else #define BOOST_PROTO_REF(x) x #endif } namespace context { template struct default_eval {}; /// INTERNAL ONLY /// #define BOOST_PROTO_UNARY_OP_RESULT(Op, Tag) \ template \ struct default_eval \ { \ private: \ static Expr &sexpr; \ static Context &sctx; \ public: \ BOOST_PROTO_DECLTYPE_(Op proto::eval(BOOST_PROTO_REF(proto::arg_c<0>(sexpr)), sctx), result_type)\ result_type operator()(Expr &expr, Context &ctx) const \ { \ return Op proto::eval(proto::arg_c<0>(expr), ctx); \ } \ }; \ /**/ /// INTERNAL ONLY /// #define BOOST_PROTO_BINARY_OP_RESULT(Op, Tag) \ template \ struct default_eval \ { \ private: \ static Expr &sexpr; \ static Context &sctx; \ public: \ BOOST_PROTO_DECLTYPE_(proto::eval(BOOST_PROTO_REF(proto::arg_c<0>(sexpr)), sctx) Op proto::eval(BOOST_PROTO_REF(proto::arg_c<1>(sexpr)), sctx), result_type)\ result_type operator()(Expr &expr, Context &ctx) const \ { \ return proto::eval(proto::arg_c<0>(expr), ctx) Op proto::eval(proto::arg_c<1>(expr), ctx);\ } \ }; \ /**/ BOOST_PROTO_UNARY_OP_RESULT(+, proto::tag::posit) BOOST_PROTO_UNARY_OP_RESULT(-, proto::tag::negate) BOOST_PROTO_UNARY_OP_RESULT(*, proto::tag::dereference) BOOST_PROTO_UNARY_OP_RESULT(~, proto::tag::complement) BOOST_PROTO_UNARY_OP_RESULT(&, proto::tag::address_of) BOOST_PROTO_UNARY_OP_RESULT(!, proto::tag::logical_not) BOOST_PROTO_UNARY_OP_RESULT(++, proto::tag::pre_inc) BOOST_PROTO_UNARY_OP_RESULT(--, proto::tag::pre_dec) BOOST_PROTO_BINARY_OP_RESULT(<<, proto::tag::shift_left) BOOST_PROTO_BINARY_OP_RESULT(>>, proto::tag::shift_right) BOOST_PROTO_BINARY_OP_RESULT(*, proto::tag::multiplies) BOOST_PROTO_BINARY_OP_RESULT(/, proto::tag::divides) BOOST_PROTO_BINARY_OP_RESULT(%, proto::tag::modulus) BOOST_PROTO_BINARY_OP_RESULT(+, proto::tag::plus) BOOST_PROTO_BINARY_OP_RESULT(-, proto::tag::minus) BOOST_PROTO_BINARY_OP_RESULT(<, proto::tag::less) BOOST_PROTO_BINARY_OP_RESULT(>, proto::tag::greater) BOOST_PROTO_BINARY_OP_RESULT(<=, proto::tag::less_equal) BOOST_PROTO_BINARY_OP_RESULT(>=, proto::tag::greater_equal) BOOST_PROTO_BINARY_OP_RESULT(==, proto::tag::equal_to) BOOST_PROTO_BINARY_OP_RESULT(!=, proto::tag::not_equal_to) BOOST_PROTO_BINARY_OP_RESULT(||, proto::tag::logical_or) BOOST_PROTO_BINARY_OP_RESULT(&&, proto::tag::logical_and) BOOST_PROTO_BINARY_OP_RESULT(&, proto::tag::bitwise_and) BOOST_PROTO_BINARY_OP_RESULT(|, proto::tag::bitwise_or) BOOST_PROTO_BINARY_OP_RESULT(^, proto::tag::bitwise_xor) BOOST_PROTO_BINARY_OP_RESULT(->*, proto::tag::mem_ptr) BOOST_PROTO_BINARY_OP_RESULT(=, proto::tag::assign) BOOST_PROTO_BINARY_OP_RESULT(<<=, proto::tag::shift_left_assign) BOOST_PROTO_BINARY_OP_RESULT(>>=, proto::tag::shift_right_assign) BOOST_PROTO_BINARY_OP_RESULT(*=, proto::tag::multiplies_assign) BOOST_PROTO_BINARY_OP_RESULT(/=, proto::tag::divides_assign) BOOST_PROTO_BINARY_OP_RESULT(%=, proto::tag::modulus_assign) BOOST_PROTO_BINARY_OP_RESULT(+=, proto::tag::plus_assign) BOOST_PROTO_BINARY_OP_RESULT(-=, proto::tag::minus_assign) BOOST_PROTO_BINARY_OP_RESULT(&=, proto::tag::bitwise_and_assign) BOOST_PROTO_BINARY_OP_RESULT(|=, proto::tag::bitwise_or_assign) BOOST_PROTO_BINARY_OP_RESULT(^=, proto::tag::bitwise_xor_assign) template struct default_eval { typedef typename mpl::if_< is_const , typename proto::result_of::arg::const_reference , typename proto::result_of::arg::reference >::type result_type; result_type operator()(Expr &expr, Context &) const { return proto::arg(expr); } }; // Handle post-increment specially. template struct default_eval { private: static Expr &sexpr; static Context &sctx; public: BOOST_PROTO_DECLTYPE_(proto::eval(BOOST_PROTO_REF(proto::arg_c<0>(sexpr)), sctx) ++, result_type) result_type operator()(Expr &expr, Context &ctx) const { return proto::eval(proto::arg_c<0>(expr), ctx) ++; } }; // Handle post-decrement specially. template struct default_eval { private: static Expr &sexpr; static Context &sctx; public: BOOST_PROTO_DECLTYPE_(proto::eval(BOOST_PROTO_REF(proto::arg_c<0>(sexpr)), sctx) --, result_type) result_type operator()(Expr &expr, Context &ctx) const { return proto::eval(proto::arg_c<0>(expr), ctx) --; } }; // Handle subscript specially. template struct default_eval { private: static Expr &sexpr; static Context &sctx; public: BOOST_PROTO_DECLTYPE_(proto::eval(BOOST_PROTO_REF(proto::arg_c<0>(sexpr)), sctx)[proto::eval(BOOST_PROTO_REF(proto::arg_c<1>(sexpr)), sctx)], result_type) result_type operator()(Expr &expr, Context &ctx) const { return proto::eval(proto::arg_c<0>(expr), ctx)[proto::eval(proto::arg_c<1>(expr), ctx)]; } }; // Handle if_else_ specially. template struct default_eval { private: static Expr &sexpr; static Context &sctx; public: BOOST_PROTO_DECLTYPE_( proto::eval(BOOST_PROTO_REF(proto::arg_c<0>(sexpr)), sctx) ? proto::eval(BOOST_PROTO_REF(proto::arg_c<1>(sexpr)), sctx) : proto::eval(BOOST_PROTO_REF(proto::arg_c<2>(sexpr)), sctx) , result_type ) result_type operator()(Expr &expr, Context &ctx) const { return proto::eval(proto::arg_c<0>(expr), ctx) ? proto::eval(proto::arg_c<1>(expr), ctx) : proto::eval(proto::arg_c<2>(expr), ctx); } }; // Handle comma specially. template struct default_eval { typedef typename proto::result_of::eval::type, Context>::type proto_arg0; typedef typename proto::result_of::eval::type, Context>::type proto_arg1; typedef typename detail::comma_result::type result_type; result_type operator()(Expr &expr, Context &ctx) const { return proto::eval(proto::arg_c<0>(expr), ctx), proto::eval(proto::arg_c<1>(expr), ctx); } }; #define BOOST_PROTO_EVAL_N_TYPE(Z, N, Data)\ typename proto::result_of::eval<\ typename proto::result_of::arg_c::type\ , BOOST_PP_TUPLE_ELEM(2, 1, Data)\ >::type #define BOOST_PROTO_EVAL_N(Z, N, Data)\ proto::eval(proto::arg_c(BOOST_PP_TUPLE_ELEM(2, 0, Data)), BOOST_PP_TUPLE_ELEM(2, 1, Data)) #define BOOST_PP_ITERATION_PARAMS_1 (3, (1, BOOST_PROTO_MAX_ARITY, )) #include BOOST_PP_ITERATE() #undef BOOST_PROTO_EVAL_N_TYPE #undef BOOST_PROTO_EVAL_N /// default_context /// struct default_context { /// default_context::eval /// template struct eval : default_eval {}; }; } // namespace context }} // namespace boost::proto #undef BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_ #undef BOOST_PROTO_DECLTYPE_ #endif #else #define N BOOST_PP_ITERATION() // Handle function specially template struct default_eval { typedef typename detail::result_of_fixup< BOOST_PROTO_EVAL_N_TYPE(1, 0, (Expr, Context)) >::type function_type; typedef typename boost::result_of< function_type( BOOST_PP_ENUM_SHIFTED(N, BOOST_PROTO_EVAL_N_TYPE, (Expr, Context)) ) >::type result_type; result_type operator ()(Expr &expr, Context &context) const { return BOOST_PROTO_EVAL_N(1, 0, (expr, context))( BOOST_PP_ENUM_SHIFTED(N, BOOST_PROTO_EVAL_N, (expr, context)) ); } }; #undef N #endif