/////////////////////////////////////////////////////////////////////////////// /// \file decltype.hpp /// Contains definition the BOOST_PROTO_DECLTYPE_() macro and assorted helpers // // Copyright 2008 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_DETAIL_DECLTYPE_HPP_EAN_04_04_2008 #define BOOST_PROTO_DETAIL_DECLTYPE_HPP_EAN_04_04_2008 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BOOST_NO_DECLTYPE # define BOOST_PROTO_DECLTYPE_(EXPR, TYPE) typedef decltype(EXPR) TYPE; #else # 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(boost::proto::detail::check_reference(EXPR)); \ struct NESTED \ : boost::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; #endif namespace boost { namespace proto { namespace detail { namespace anyns { //////////////////////////////////////////////////////////////////////////////////////////// struct any { any(...); any operator=(any); any operator[](any); #define M0(Z, N, DATA) any operator()(BOOST_PP_ENUM_PARAMS_Z(Z, N, any BOOST_PP_INTERCEPT)); BOOST_PP_REPEAT(BOOST_PROTO_MAX_ARITY, M0, ~) #undef M0 template operator T &() const volatile; any operator+(); any operator-(); any operator*(); any operator&(); any operator~(); any operator!(); any operator++(); any operator--(); any operator++(int); any operator--(int); friend any operator<<(any, any); friend any operator>>(any, any); friend any operator*(any, any); friend any operator/(any, any); friend any operator%(any, any); friend any operator+(any, any); friend any operator-(any, any); friend any operator<(any, any); friend any operator>(any, any); friend any operator<=(any, any); friend any operator>=(any, any); friend any operator==(any, any); friend any operator!=(any, any); friend any operator||(any, any); friend any operator&&(any, any); friend any operator&(any, any); friend any operator|(any, any); friend any operator^(any, any); friend any operator,(any, any); friend any operator->*(any, any); friend any operator<<=(any, any); friend any operator>>=(any, any); friend any operator*=(any, any); friend any operator/=(any, any); friend any operator%=(any, any); friend any operator+=(any, any); friend any operator-=(any, any); friend any operator&=(any, any); friend any operator|=(any, any); friend any operator^=(any, any); }; } using anyns::any; //////////////////////////////////////////////////////////////////////////////////////////// template struct as_mutable { typedef T &type; }; template struct as_mutable { typedef T &type; }; template struct as_mutable { typedef T &type; }; //////////////////////////////////////////////////////////////////////////////////////////// template T make(); //////////////////////////////////////////////////////////////////////////////////////////// template typename as_mutable::type make_mutable(); //////////////////////////////////////////////////////////////////////////////////////////// template struct subscript_wrapper : T { using T::operator[]; #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500)) any operator[](any const volatile &) const volatile; #else any operator[](any const &) const volatile; #endif }; //////////////////////////////////////////////////////////////////////////////////////////// template struct as_subscriptable { typedef typename mpl::if_c< is_class::value , subscript_wrapper , T >::type type; }; template struct as_subscriptable { typedef typename mpl::if_c< is_class::value , subscript_wrapper const , T const >::type type; }; template struct as_subscriptable { typedef typename mpl::if_c< is_class::value , subscript_wrapper & , T & >::type type; }; template struct as_subscriptable { typedef typename mpl::if_c< is_class::value , subscript_wrapper const & , T const & >::type type; }; //////////////////////////////////////////////////////////////////////////////////////////// template typename as_subscriptable::type make_subscriptable(); //////////////////////////////////////////////////////////////////////////////////////////// template char check_reference(T &); template char (&check_reference(T const &))[2]; namespace has_get_pointerns { using boost::get_pointer; void *(&get_pointer(...))[2]; //////////////////////////////////////////////////////////////////////////////////////////// template struct has_get_pointer { BOOST_STATIC_CONSTANT(bool, value = sizeof(void *) == sizeof(get_pointer(make()))); typedef mpl::bool_ type; }; } using has_get_pointerns::has_get_pointer; //////////////////////////////////////////////////////////////////////////////////////////// template struct classtypeof; template struct classtypeof { typedef U type; }; #define BOOST_PP_LOCAL_MACRO(N) \ template \ struct classtypeof \ { \ typedef U type; \ }; \ template \ struct classtypeof \ { \ typedef U type; \ }; \ /**/ #define BOOST_PP_LOCAL_LIMITS (0, BOOST_PROTO_MAX_ARITY) #include BOOST_PP_LOCAL_ITERATE() //////////////////////////////////////////////////////////////////////////////////////////// template T &lvalue(T &t) { return t; } template T const &lvalue(T const &t) { return t; } //////////////////////////////////////////////////////////////////////////////////////////// template U *proto_get_pointer(T &t, V *, U *) { return boost::addressof(t); } template U const *proto_get_pointer(T &t, V *, U const *) { return boost::addressof(t); } template V *proto_get_pointer(T &t, V *, ...) { return get_pointer(t); } //////////////////////////////////////////////////////////////////////////////////////////// #define BOOST_PROTO_USE_GET_POINTER() \ using namespace boost::proto::detail::get_pointerns \ /**/ #define BOOST_PROTO_GET_POINTER(Type, Obj) \ boost::proto::detail::proto_get_pointer( \ boost::proto::detail::lvalue(Obj) \ , (true ? 0 : get_pointer(Obj)) \ , (true ? 0 : boost::addressof(boost::proto::detail::lvalue(Obj))) \ ) \ /**/ //////////////////////////////////////////////////////////////////////////////////////////// namespace get_pointerns { using boost::get_pointer; template typename disable_if_c::value, T *>::type get_pointer(T &t) { return boost::addressof(t); } template typename disable_if_c::value, T const *>::type get_pointer(T const &t) { return boost::addressof(t); } char test_ptr_to_const(void *); char (&test_ptr_to_const(void const *))[2]; template char test_V_is_a_U(U *); template char test_V_is_a_U(U const *); template char (&test_V_is_a_U(...))[2]; //////////////////////////////////////////////////////////////////////////////////////////// // sun workaround template struct sun_workaround_helper { typedef T type; }; template struct result_of_2 : boost::tr1_result_of {}; template struct result_of_2 , typename enable_if_c::value>::type > { BOOST_STATIC_CONSTANT(bool, is_V_a_smart_ptr = 2 == sizeof(test_V_is_a_U(&lvalue(make())))); BOOST_STATIC_CONSTANT(bool, is_ptr_to_const = 2 == sizeof(test_ptr_to_const(BOOST_PROTO_GET_POINTER(U, make())))); // If V is not a U, then it is a (smart) pointer and we can always return an lvalue. // Otherwise, we can only return an lvalue if we are given one. typedef typename mpl::eval_if_c< (is_V_a_smart_ptr || is_reference::value) , mpl::eval_if_c< is_ptr_to_const , add_reference::type> , add_reference > , mpl::identity >::type type; }; //////////////////////////////////////////////////////////////////////////////////////////// // result_of_ is a wrapper around boost::result_of that also handles "invocations" of // member object pointers. template struct result_of_ : result_of_2 > {}; template struct result_of_::value>::type> { BOOST_STATIC_CONSTANT(bool, is_V_a_smart_ptr = 2 == sizeof(test_V_is_a_U(&lvalue(make())))); BOOST_STATIC_CONSTANT(bool, is_ptr_to_const = 2 == sizeof(test_ptr_to_const(BOOST_PROTO_GET_POINTER(U, make())))); // If V is not a U, then it is a (smart) pointer and we can always return an lvalue. // Otherwise, we can only return an lvalue if we are given one. typedef typename mpl::eval_if_c< (is_V_a_smart_ptr || is_reference::value) , mpl::eval_if_c< is_ptr_to_const , add_reference::type> , add_reference > , mpl::identity >::type type; }; //////////////////////////////////////////////////////////////////////////////////////////// template< typename T , typename U , bool IsMemPtr = is_member_object_pointer< typename remove_reference::type >::value > struct mem_ptr_fun { BOOST_PROTO_DECLTYPE_( proto::detail::make_mutable() ->* proto::detail::make() , result_type ) result_type operator()( typename add_reference::type>::type t , typename add_reference::type>::type u ) const { return t ->* u; } }; //////////////////////////////////////////////////////////////////////////////////////////// template struct mem_ptr_fun { typedef typename classtypeof< typename remove_const< typename remove_reference::type >::type >::type V; BOOST_PROTO_DECLTYPE_( BOOST_PROTO_GET_POINTER(V, proto::detail::make_mutable()) ->* proto::detail::make() , result_type ) result_type operator()( typename add_reference::type>::type t , U u ) const { return BOOST_PROTO_GET_POINTER(V, t) ->* u; } }; } using get_pointerns::result_of_; using get_pointerns::mem_ptr_fun; //////////////////////////////////////////////////////////////////////////////////////////// template struct comma_result { BOOST_PROTO_DECLTYPE_((proto::detail::make(), proto::detail::make()), type) }; template struct comma_result { typedef void type; }; template struct comma_result { typedef A1 type; }; template<> struct comma_result { typedef void type; }; //////////////////////////////////////////////////////////////////////////////////////////// // normalize a function type for use with boost::result_of template struct result_of_fixup : mpl::if_c::value, 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 {}; template struct result_of_fixup { typedef R T::*type; }; 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>)); template struct memfun { typedef typename remove_const::type>::type pmf_type; typedef typename classtypeof::type V; typedef typename boost::result_of::type result_type; memfun(T t, PMF p) : obj(t) , pmf(p) {} result_type operator()() const { BOOST_PROTO_USE_GET_POINTER(); return (BOOST_PROTO_GET_POINTER(V, obj) ->* pmf)(); } #define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A_const_ref, A_const_ref_a, a) \ template \ result_type operator()(A_const_ref_a(N)) const \ { \ BOOST_PROTO_USE_GET_POINTER(); \ return (BOOST_PROTO_GET_POINTER(V, obj) ->* pmf)(a(N)); \ } \ /**/ #define BOOST_PROTO_LOCAL_a BOOST_PROTO_a #define BOOST_PROTO_LOCAL_LIMITS (1, BOOST_PROTO_MAX_ARITY) #include BOOST_PROTO_LOCAL_ITERATE() private: T obj; PMF pmf; }; } // namespace detail }} #endif