/////////////////////////////////////////////////////////////////////////////// /// \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 #include #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined #endif // We're STILL using Boost.Typeof on MSVC even for msvc-11.0 because of this bug: // https://connect.microsoft.com/VisualStudio/feedback/details/765392/decltype-of-a-pointer-to-member-operator-gets-ref-qualification-wrong #if !defined(BOOST_NO_CXX11_DECLTYPE) && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700)) # 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 BOOST_PP_CAT(sz, NESTED) = sizeof(boost::proto::detail::check_reference(EXPR));\ struct NESTED \ : boost::mpl::if_c< \ 1 == BOOST_PP_CAT(sz, NESTED) \ , 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 { //////////////////////////////////////////////////////////////////////////////////////////// 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 { static const bool value = sizeof(void *) == sizeof(get_pointer(make())); typedef mpl::bool_ type; }; } using has_get_pointerns::has_get_pointer; //////////////////////////////////////////////////////////////////////////////////////////// template struct class_member_traits; template struct class_member_traits { typedef U class_type; typedef T result_type; }; // Other specializations are generated by the preprocessor #include //////////////////////////////////////////////////////////////////////////////////////////// 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]; //////////////////////////////////////////////////////////////////////////////////////////// // result_of_ is a wrapper around boost::result_of that also handles "invocations" of // member object pointers. template struct result_of_ : BOOST_PROTO_RESULT_OF {}; template struct result_of_::value>::type> { static const bool is_V_a_smart_ptr = 2 == sizeof(test_V_is_a_U(&lvalue(make()))); static const 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 class_member_traits< typename uncvref::type >::class_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 uncvref::type pmf_type; typedef typename class_member_traits::class_type V; typedef typename class_member_traits::result_type result_type; memfun(T t, pmf_type p) : obj(t) , pmf(p) {} result_type operator()() const { BOOST_PROTO_USE_GET_POINTER(); return (BOOST_PROTO_GET_POINTER(V, obj) ->* pmf)(); } // Other overloads generated by the preprocessor #include private: T obj; pmf_type pmf; }; } // namespace detail }} #if defined(_MSC_VER) # pragma warning(pop) #endif #endif