Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r53334 - in trunk: boost/proto/context boost/proto/detail boost/proto/transform libs/proto/test
From: eric_at_[hidden]
Date: 2009-05-28 00:58:48


Author: eric_niebler
Date: 2009-05-28 00:58:45 EDT (Thu, 28 May 2009)
New Revision: 53334
URL: http://svn.boost.org/trac/boost/changeset/53334

Log:
saner default evaluation behavior for member (object|function) pointers
Added:
   trunk/libs/proto/test/mem_ptr.cpp (contents, props changed)
Text files modified:
   trunk/boost/proto/context/default.hpp | 21 ++-
   trunk/boost/proto/detail/decltype.hpp | 239 ++++++++++++++++++++-------------------
   trunk/boost/proto/transform/default.hpp | 20 ++-
   trunk/libs/proto/test/Jamfile.v2 | 1
   4 files changed, 150 insertions(+), 131 deletions(-)

Modified: trunk/boost/proto/context/default.hpp
==============================================================================
--- trunk/boost/proto/context/default.hpp (original)
+++ trunk/boost/proto/context/default.hpp 2009-05-28 00:58:45 EDT (Thu, 28 May 2009)
@@ -154,11 +154,12 @@
                 typedef typename result_of::child_c<Expr, 1>::type e1;
                 typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0;
                 typedef typename proto::result_of::eval<UNREF(e1), Context>::type r1;
+ typedef typename remove_const<typename remove_reference<r1>::type>::type uncvref_r1;
             public:
- typedef typename detail::mem_ptr_fun<r0, r1>::result_type result_type;
+ typedef typename detail::mem_ptr_fun<r0, uncvref_r1>::result_type result_type;
                 result_type operator ()(Expr &expr, Context &ctx) const
                 {
- return detail::mem_ptr_fun<r0, r1>()(
+ return detail::mem_ptr_fun<r0, uncvref_r1>()(
                         proto::eval(proto::child_c<0>(expr), ctx)
                       , proto::eval(proto::child_c<1>(expr), ctx)
                     );
@@ -174,6 +175,7 @@
                 typedef typename result_of::child_c<Expr, 1>::type e1;
                 typedef typename proto::result_of::eval<UNREF(e0), Context>::type r0;
                 typedef typename proto::result_of::eval<UNREF(e1), Context>::type r1;
+ typedef typename remove_const<typename remove_reference<r1>::type>::type uncvref_r1;
             public:
                 typedef detail::memfun<r0, r1> result_type;
                 result_type const operator ()(Expr &expr, Context &ctx) const
@@ -353,14 +355,16 @@
 
                 result_type invoke(Expr &expr, Context &context, mpl::true_, mpl::false_) const
                 {
- using namespace detail::get_pointer_;
- return (get_pointer(EVAL(~, 1, expr)) ->* EVAL(~, 0, expr))();
+ BOOST_PROTO_USE_GET_POINTER();
+ typedef typename detail::classtypeof<function_type>::type class_type;
+ return (BOOST_PROTO_GET_POINTER(class_type, EVAL(~, 1, expr)) ->* EVAL(~, 0, expr))();
                 }
 
                 result_type invoke(Expr &expr, Context &context, mpl::false_, mpl::true_) const
                 {
- using namespace detail::get_pointer_;
- return (get_pointer(EVAL(~, 1, expr)) ->* EVAL(~, 0, expr));
+ BOOST_PROTO_USE_GET_POINTER();
+ typedef typename detail::classtypeof<function_type>::type class_type;
+ return (BOOST_PROTO_GET_POINTER(class_type, EVAL(~, 1, expr)) ->* EVAL(~, 0, expr));
                 }
             };
 
@@ -421,8 +425,9 @@
             result_type invoke(Expr &expr, Context &context, mpl::true_) const
             {
                 #define M0(Z, M, expr) BOOST_PP_COMMA_IF(BOOST_PP_SUB(M, 2)) EVAL(Z, M, expr)
- using namespace detail::get_pointer_;
- return (get_pointer(EVAL(~, 1, expr)) ->* EVAL(~, 0, expr))(
+ BOOST_PROTO_USE_GET_POINTER();
+ typedef typename detail::classtypeof<function_type>::type class_type;
+ return (BOOST_PROTO_GET_POINTER(class_type, EVAL(~, 1, expr)) ->* EVAL(~, 0, expr))(
                     BOOST_PP_REPEAT_FROM_TO(2, N, M0, expr)
                 );
                 #undef M0

Modified: trunk/boost/proto/detail/decltype.hpp
==============================================================================
--- trunk/boost/proto/detail/decltype.hpp (original)
+++ trunk/boost/proto/detail/decltype.hpp 2009-05-28 00:58:45 EDT (Thu, 28 May 2009)
@@ -18,7 +18,8 @@
 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
 #include <boost/mpl/if.hpp>
-#include <boost/mpl/and.hpp>
+#include <boost/mpl/eval_if.hpp>
+#include <boost/mpl/identity.hpp>
 #include <boost/type_traits/is_class.hpp>
 #include <boost/type_traits/remove_cv.hpp>
 #include <boost/type_traits/remove_reference.hpp>
@@ -31,6 +32,7 @@
 #include <boost/utility/addressof.hpp>
 #include <boost/utility/result_of.hpp>
 #include <boost/utility/enable_if.hpp>
+#include <boost/proto/repeat.hpp>
 #include <boost/proto/detail/suffix.hpp> // must be last include
 
 // If we're generating doxygen documentation, hide all the nasty
@@ -110,7 +112,7 @@
                 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);
@@ -123,9 +125,9 @@
                 friend any operator^=(any, any);
             };
         }
-
+
         using anyns::any;
-
+
         ////////////////////////////////////////////////////////////////////////////////////////////
         template<typename T>
         struct as_mutable
@@ -227,7 +229,7 @@
         template<typename T>
         char (&check_reference(T const &))[2];
 
- namespace has_get_pointer_
+ namespace has_get_pointerns
         {
             using boost::get_pointer;
             void *(&get_pointer(...))[2];
@@ -236,91 +238,146 @@
             template<typename T>
             struct has_get_pointer
             {
- static T &t;
- BOOST_STATIC_CONSTANT(bool, value = sizeof(void *) == sizeof(get_pointer(t)));
+ BOOST_STATIC_CONSTANT(bool, value = sizeof(void *) == sizeof(get_pointer(make<T &>())));
                 typedef mpl::bool_<value> type;
             };
         }
 
- using has_get_pointer_::has_get_pointer;
-
+ using has_get_pointerns::has_get_pointer;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ template<typename T>
+ struct classtypeof;
+
+ template<typename T, typename U>
+ struct classtypeof<T U::*>
+ {
+ typedef U type;
+ };
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ template<typename T>
+ T &lvalue(T &t)
+ {
+ return t;
+ }
+
+ template<typename T>
+ T const &lvalue(T const &t)
+ {
+ return t;
+ }
+
         ////////////////////////////////////////////////////////////////////////////////////////////
- namespace get_pointer_
+ template<typename U, typename V>
+ U *proto_get_pointer(V *, U *u)
+ {
+ return u;
+ }
+
+ template<typename U, typename V>
+ U const *proto_get_pointer(V *, U const *u)
+ {
+ return u;
+ }
+
+ template<typename U, typename V>
+ V *proto_get_pointer(V *v, ...)
+ {
+ return v;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ #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<typename boost::remove_reference<Type>::type>( \
+ get_pointer(Obj) \
+ , boost::addressof(boost::proto::detail::lvalue(Obj)) \
+ ) \
+ /**/
+
+ ////////////////////////////////////////////////////////////////////////////////////////////
+ namespace get_pointerns
         {
             using boost::get_pointer;
 
             template<typename T>
- typename disable_if<has_get_pointer<T>, T *>::type
+ typename disable_if_c<has_get_pointer<T>::value, T *>::type
             get_pointer(T &t)
             {
                 return boost::addressof(t);
             }
 
             template<typename T>
- typename disable_if<has_get_pointer<T>, T const *>::type
+ typename disable_if_c<has_get_pointer<T>::value, T const *>::type
             get_pointer(T const &t)
             {
                 return boost::addressof(t);
             }
-
- template<typename U>
- char test_ptr_to_const(U *);
 
- template<typename U>
- char (&test_ptr_to_const(U const *))[2];
+ char test_ptr_to_const(void *);
+ char (&test_ptr_to_const(void const *))[2];
 
- template<typename T>
- struct is_ref_to_const
- {
- static T t;
- BOOST_STATIC_CONSTANT(bool, value = 2 == sizeof(test_ptr_to_const(get_pointer(t))));
- typedef mpl::bool_<value> type;
- };
+ template<typename U> char test_V_is_a_U(U *);
+ template<typename U> char test_V_is_a_U(U const *);
+ template<typename U> char (&test_V_is_a_U(...))[2];
 
             ////////////////////////////////////////////////////////////////////////////////////////////
- template<
- typename T
- , typename U
- , bool IsMemPtr = is_member_object_pointer<
- typename remove_reference<U>::type
- >::value
- >
- struct mem_ptr_fun
+ // result_of_ is a wrapper around boost::result_of that also handles "invocations" of
+ // member object pointers.
+ template<typename T, typename Void = void>
+ struct result_of_
+ : boost::result_of<T>
+ {};
+
+ template<typename T, typename U, typename V>
+ struct result_of_<T U::*(V), typename enable_if_c<is_member_object_pointer<T U::*>::value>::type>
             {
- BOOST_PROTO_DECLTYPE_(
- proto::detail::make_mutable<T>() ->* proto::detail::make<U>()
- , result_type
- )
+ BOOST_STATIC_CONSTANT(bool, is_V_a_smart_ptr = 2 == sizeof(test_V_is_a_U<U>(&lvalue(make<V>()))));
+ BOOST_STATIC_CONSTANT(bool, is_ptr_to_const = 2 == sizeof(test_ptr_to_const(BOOST_PROTO_GET_POINTER(U, make<V>()))));
 
- result_type operator()(
- typename add_reference<typename add_const<T>::type>::type t
- , typename add_reference<typename add_const<U>::type>::type u
- ) const
- {
- return t ->* u;
- }
+ // 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<V>::value)
+ , mpl::eval_if_c<
+ is_ptr_to_const
+ , add_reference<typename add_const<T>::type>
+ , add_reference<T>
+ >
+ , mpl::identity<T>
+ >::type
+ type;
             };
 
             ////////////////////////////////////////////////////////////////////////////////////////////
             template<typename T, typename U>
- struct mem_ptr_fun<T, U, true>
+ struct mem_ptr_fun;
+
+ template<typename T, typename U, typename V>
+ struct mem_ptr_fun<T, U V::*>
             {
                 BOOST_PROTO_DECLTYPE_(
- get_pointer(proto::detail::make_mutable<T>()) ->* proto::detail::make<U>()
+ BOOST_PROTO_GET_POINTER(V, proto::detail::make_mutable<T>()) ->* proto::detail::make<U V::*>()
                   , result_type
                 )
 
                 result_type operator()(
                     typename add_reference<typename add_const<T>::type>::type t
- , typename add_reference<typename add_const<U>::type>::type u
+ , U V::*u
                 ) const
                 {
- return get_pointer(t) ->* u;
+ return BOOST_PROTO_GET_POINTER(V, t) ->* u;
                 }
             };
         }
 
- using get_pointer_::mem_ptr_fun;
+ using get_pointerns::result_of_;
+ using get_pointerns::mem_ptr_fun;
 
         ////////////////////////////////////////////////////////////////////////////////////////////
         template<typename A0, typename A1>
@@ -348,58 +405,7 @@
         };
 
         ////////////////////////////////////////////////////////////////////////////////////////////
- template<typename T>
- struct result_of_member;
-
- template<typename T, typename U>
- struct result_of_member<T U::*>
- {
- typedef T type;
- };
-
- template<typename T, typename Void = void>
- struct result_of_
- : boost::result_of<T>
- {};
-
- template<typename T, typename U>
- struct result_of_<T(U), typename enable_if_c<is_member_object_pointer<T>::value>::type>
- {
- typedef
- typename mpl::if_c<
- mpl::and_<
- has_get_pointer<U>
- , get_pointer_::is_ref_to_const<U const &>
- >::value
- , typename add_reference<
- typename add_const<
- typename result_of_member<T>::type
- >::type
- >::type
- , typename result_of_member<T>::type
- >::type
- type;
- };
-
- template<typename T, typename U>
- struct result_of_<T(U &), typename enable_if_c<is_member_object_pointer<T>::value>::type>
- {
- typedef
- typename mpl::if_c<
- get_pointer_::is_ref_to_const<U &>::value
- , typename add_reference<
- typename add_const<
- typename result_of_member<T>::type
- >::type
- >::type
- , typename add_reference<
- typename result_of_member<T>::type
- >::type
- >::type
- type;
- };
-
- ////////////////////////////////////////////////////////////////////////////////////////////
+ // normalize a function type for use with boost::result_of
         template<typename T, typename U = T>
         struct result_of_fixup
           : mpl::if_c<is_function<T>::value, T *, U>
@@ -443,36 +449,39 @@
         //BOOST_MPL_ASSERT((is_same<void(*)(), result_of_fixup<void(&)()>::type>));
 
         template<typename T, typename PMF>
- struct memfun
+ struct memfun;
+
+ template<typename T, typename U, typename V>
+ struct memfun<T, U V::*>
         {
- typedef typename remove_const<typename remove_reference<PMF>::type>::type pmf_type;
- typedef typename boost::result_of<pmf_type(T)>::type result_type;
+ typedef typename boost::result_of<U V::*(T)>::type result_type;
 
- memfun(T t, PMF p)
+ memfun(T t, U V::*p)
               : obj(t)
               , pmf(p)
             {}
-
+
             result_type operator()() const
             {
- using namespace get_pointer_;
- return (get_pointer(obj) ->* pmf)();
+ BOOST_PROTO_USE_GET_POINTER();
+ return (BOOST_PROTO_GET_POINTER(V, obj) ->* pmf)();
             }
 
- #define M0(Z, N, DATA) \
- template<BOOST_PP_ENUM_PARAMS_Z(Z, N, typename A)> \
- result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS_Z(Z, N, A, const &a)) const \
+ #define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A_const_ref, A_const_ref_a, a) \
+ template<typename_A(N)> \
+ result_type operator()(A_const_ref_a(N)) const \
             { \
- using namespace get_pointer_; \
- return (get_pointer(obj) ->* pmf)(BOOST_PP_ENUM_PARAMS_Z(Z, N, a)); \
+ BOOST_PROTO_USE_GET_POINTER(); \
+ return (BOOST_PROTO_GET_POINTER(V, obj) ->* pmf)(a(N)); \
             } \
             /**/
- BOOST_PP_REPEAT_FROM_TO(1, BOOST_PROTO_MAX_ARITY, M0, ~)
- #undef M0
+ #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;
+ U V::*pmf;
         };
 
     } // namespace detail

Modified: trunk/boost/proto/transform/default.hpp
==============================================================================
--- trunk/boost/proto/transform/default.hpp (original)
+++ trunk/boost/proto/transform/default.hpp 2009-05-28 00:58:45 EDT (Thu, 28 May 2009)
@@ -158,8 +158,9 @@
                 typedef typename result_of::child_c<Expr, 1>::type e1;
                 typedef typename Grammar::template impl<e0, State, Data>::result_type r0;
                 typedef typename Grammar::template impl<e1, State, Data>::result_type r1;
+ typedef typename remove_const<typename remove_reference<r1>::type>::type uncvref_r1;
             public:
- typedef typename detail::mem_ptr_fun<r0, r1>::result_type result_type;
+ typedef typename detail::mem_ptr_fun<r0, uncvref_r1>::result_type result_type;
                 result_type operator ()(
                     typename memfun_impl::expr_param e
                   , typename memfun_impl::state_param s
@@ -168,7 +169,7 @@
                 {
                     typename Grammar::template impl<e0, State, Data> t0;
                     typename Grammar::template impl<e1, State, Data> t1;
- return detail::mem_ptr_fun<r0, r1>()(
+ return detail::mem_ptr_fun<r0, uncvref_r1>()(
                         t0(proto::child_c<0>(e), s, d)
                       , t1(proto::child_c<1>(e), s, d)
                     );
@@ -420,8 +421,9 @@
                   , mpl::false_
                 ) const
                 {
- using namespace detail::get_pointer_;
- return (get_pointer(EVAL(~, 1, e)) ->* EVAL(~, 0, e))();
+ BOOST_PROTO_USE_GET_POINTER();
+ typedef typename detail::classtypeof<function_type>::type class_type;
+ return (BOOST_PROTO_GET_POINTER(class_type, EVAL(~, 1, e)) ->* EVAL(~, 0, e))();
                 }
 
                 result_type invoke(
@@ -432,8 +434,9 @@
                   , mpl::true_
                 ) const
                 {
- using namespace detail::get_pointer_;
- return (get_pointer(EVAL(~, 1, e)) ->* EVAL(~, 0, e));
+ BOOST_PROTO_USE_GET_POINTER();
+ typedef typename detail::classtypeof<function_type>::type class_type;
+ return (BOOST_PROTO_GET_POINTER(class_type, EVAL(~, 1, e)) ->* EVAL(~, 0, e));
                 }
             };
 
@@ -512,8 +515,9 @@
             ) const
             {
                 #define M0(Z, M, e) BOOST_PP_COMMA_IF(BOOST_PP_SUB(M, 2)) EVAL(Z, M, e)
- using namespace detail::get_pointer_;
- return (get_pointer(EVAL(~, 1, e)) ->* EVAL(~, 0, e))(
+ BOOST_PROTO_USE_GET_POINTER();
+ typedef typename detail::classtypeof<function_type>::type class_type;
+ return (BOOST_PROTO_GET_POINTER(class_type, EVAL(~, 1, e)) ->* EVAL(~, 0, e))(
                     BOOST_PP_REPEAT_FROM_TO(2, N, M0, e)
                 );
                 #undef M0

Modified: trunk/libs/proto/test/Jamfile.v2
==============================================================================
--- trunk/libs/proto/test/Jamfile.v2 (original)
+++ trunk/libs/proto/test/Jamfile.v2 2009-05-28 00:58:45 EDT (Thu, 28 May 2009)
@@ -30,6 +30,7 @@
         [ run toy_spirit.cpp ]
         [ run toy_spirit2.cpp ]
         [ run noinvoke.cpp ]
+ [ run mem_ptr.cpp : : : <toolset>msvc:<cxxflags>/wd4355 ]
         [ compile bug2407.cpp ]
     ;
 

Added: trunk/libs/proto/test/mem_ptr.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/proto/test/mem_ptr.cpp 2009-05-28 00:58:45 EDT (Thu, 28 May 2009)
@@ -0,0 +1,303 @@
+///////////////////////////////////////////////////////////////////////////////
+// mem_ptr.hpp
+//
+// Copyright 2009 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)
+
+#include <boost/mpl/print.hpp>
+#include <iostream>
+#include <boost/shared_ptr.hpp>
+#include <boost/proto/proto.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/utility/result_of.hpp>
+#include <boost/test/unit_test.hpp>
+
+namespace proto = boost::proto;
+using proto::_;
+
+struct evaluator
+ : proto::when<_, proto::_default<evaluator> >
+{};
+
+template<typename Ret, typename Expr>
+void assert_result_type(Expr &)
+{
+ // check that the return type as calculated by the _default transform
+ // is correct.
+ BOOST_MPL_ASSERT((
+ boost::is_same<
+ Ret
+ , typename boost::result_of<evaluator(Expr &)>::type
+ >
+ ));
+
+ // check that the return type as calculated by the default_context
+ // is correct.
+ BOOST_MPL_ASSERT((
+ boost::is_same<
+ Ret
+ , typename boost::result_of<proto::functional::eval(Expr &, proto::default_context &)>::type
+ >
+ ));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+struct S
+{
+ S() : x(-42) {}
+ int x;
+};
+
+// like a normal terminal except with an operator() that can
+// accept non-const lvalues (Proto's only accepts const lvalues)
+template<typename T, typename Dummy = proto::is_proto_expr>
+struct my_terminal
+{
+ typedef typename proto::terminal<T>::type my_terminal_base;
+ BOOST_PROTO_BASIC_EXTENDS(my_terminal_base, my_terminal, proto::default_domain)
+
+ template<typename A0>
+ typename proto::result_of::make_expr<proto::tag::function, my_terminal const &, A0 &>::type const
+ operator()(A0 &a0) const
+ {
+ return proto::make_expr<proto::tag::function>(boost::cref(*this), boost::ref(a0));
+ }
+
+ template<typename A0>
+ typename proto::result_of::make_expr<proto::tag::function, my_terminal const &, A0 const &>::type const
+ operator()(A0 const &a0) const
+ {
+ return proto::make_expr<proto::tag::function>(boost::cref(*this), boost::cref(a0));
+ }
+};
+
+my_terminal<int S::*> test1 = {{ &S::x }};
+
+// Some tests with the default transform
+void test_refs_transform()
+{
+ S s;
+ BOOST_REQUIRE_EQUAL(s.x, -42);
+
+ // Check that evaluating a memptr invocation with a
+ // non-const lvalue argument yields the member as a
+ // non-const lvalue
+ assert_result_type<int &>(test1(s));
+ evaluator()(test1(s)) = 0;
+ BOOST_CHECK_EQUAL(s.x, 0);
+
+ // Ditto for reference_wrappers
+ assert_result_type<int &>(test1(boost::ref(s)));
+ evaluator()(test1(boost::ref(s))) = 42;
+ BOOST_CHECK_EQUAL(s.x, 42);
+
+ // Check that evaluating a memptr invocation with a
+ // const lvalue argument yields the member as a
+ // const lvalue
+ S const &rcs = s;
+ assert_result_type<int const &>(test1(rcs));
+ int const &s_x = evaluator()(test1(rcs));
+ BOOST_CHECK_EQUAL(&s.x, &s_x);
+}
+
+// Some tests with the default context
+void test_refs_context()
+{
+ proto::default_context ctx;
+ S s;
+ BOOST_REQUIRE_EQUAL(s.x, -42);
+
+ // Check that evaluating a memptr invocation with a
+ // non-const lvalue argument yields the member as a
+ // non-const lvalue
+ assert_result_type<int &>(test1(s));
+ proto::eval(test1(s), ctx) = 0;
+ BOOST_CHECK_EQUAL(s.x, 0);
+
+ // Ditto for reference_wrappers
+ assert_result_type<int &>(test1(boost::ref(s)));
+ proto::eval(test1(boost::ref(s)), ctx) = 42;
+ BOOST_CHECK_EQUAL(s.x, 42);
+
+ // Check that evaluating a memptr invocation with a
+ // const lvalue argument yields the member as a
+ // const lvalue
+ S const &rcs = s;
+ assert_result_type<int const &>(test1(rcs));
+ int const &s_x = proto::eval(test1(rcs), ctx);
+ BOOST_CHECK_EQUAL(&s.x, &s_x);
+}
+
+void test_ptrs_transform()
+{
+ S s;
+ BOOST_REQUIRE_EQUAL(s.x, -42);
+
+ // Check that evaluating a memptr invocation with a
+ // pointer to a non-const argument yields the member as a
+ // non-const lvalue
+ assert_result_type<int &>(test1(&s));
+ evaluator()(test1(&s)) = 0;
+ BOOST_CHECK_EQUAL(s.x, 0);
+
+ S* ps = &s;
+ assert_result_type<int &>(test1(ps));
+ evaluator()(test1(ps)) = 42;
+ BOOST_CHECK_EQUAL(s.x, 42);
+
+ boost::shared_ptr<S> const sp(new S);
+ BOOST_REQUIRE_EQUAL(sp->x, -42);
+
+ // Ditto for shared_ptr (which hook the get_pointer()
+ // customization point)
+ assert_result_type<int &>(test1(sp));
+ evaluator()(test1(sp)) = 0;
+ BOOST_CHECK_EQUAL(sp->x, 0);
+
+ // Check that evaluating a memptr invocation with a
+ // const lvalue argument yields the member as a
+ // const lvalue
+ S const &rcs = s;
+ assert_result_type<int const &>(test1(&rcs));
+ int const &s_x0 = evaluator()(test1(&rcs));
+ BOOST_CHECK_EQUAL(&s.x, &s_x0);
+
+ S const *pcs = &s;
+ assert_result_type<int const &>(test1(pcs));
+ int const &s_x1 = evaluator()(test1(pcs));
+ BOOST_CHECK_EQUAL(&s.x, &s_x1);
+
+ boost::shared_ptr<S const> spc(new S);
+ BOOST_REQUIRE_EQUAL(spc->x, -42);
+
+ assert_result_type<int const &>(test1(spc));
+ int const &s_x2 = evaluator()(test1(spc));
+ BOOST_CHECK_EQUAL(&spc->x, &s_x2);
+}
+
+void test_ptrs_context()
+{
+ proto::default_context ctx;
+ S s;
+ BOOST_REQUIRE_EQUAL(s.x, -42);
+
+ // Check that evaluating a memptr invocation with a
+ // pointer to a non-const argument yields the member as a
+ // non-const lvalue
+ assert_result_type<int &>(test1(&s));
+ proto::eval(test1(&s), ctx) = 0;
+ BOOST_CHECK_EQUAL(s.x, 0);
+
+ S* ps = &s;
+ assert_result_type<int &>(test1(ps));
+ proto::eval(test1(ps), ctx) = 42;
+ BOOST_CHECK_EQUAL(s.x, 42);
+
+ boost::shared_ptr<S> const sp(new S);
+ BOOST_REQUIRE_EQUAL(sp->x, -42);
+
+ // Ditto for shared_ptr (which hook the get_pointer()
+ // customization point)
+ assert_result_type<int &>(test1(sp));
+ proto::eval(test1(sp), ctx) = 0;
+ BOOST_CHECK_EQUAL(sp->x, 0);
+
+ // Check that evaluating a memptr invocation with a
+ // const lvalue argument yields the member as a
+ // const lvalue
+ S const &rcs = s;
+ assert_result_type<int const &>(test1(&rcs));
+ int const &s_x0 = proto::eval(test1(&rcs), ctx);
+ BOOST_CHECK_EQUAL(&s.x, &s_x0);
+
+ S const *pcs = &s;
+ assert_result_type<int const &>(test1(pcs));
+ int const &s_x1 = proto::eval(test1(pcs), ctx);
+ BOOST_CHECK_EQUAL(&s.x, &s_x1);
+
+ boost::shared_ptr<S const> spc(new S);
+ BOOST_REQUIRE_EQUAL(spc->x, -42);
+
+ assert_result_type<int const &>(test1(spc));
+ int const &s_x2 = proto::eval(test1(spc), ctx);
+ BOOST_CHECK_EQUAL(&spc->x, &s_x2);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+struct T
+{
+ int x;
+};
+
+proto::terminal<int T::*>::type test2 = { &T::x };
+
+int const *get_pointer(T const &t)
+{
+ return &t.x;
+}
+
+void with_get_pointer_transform()
+{
+ T t;
+ evaluator()(test2(t));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+template<typename T>
+struct dumb_ptr
+{
+ dumb_ptr(T *p_) : p(p_) {}
+
+ friend T const *get_pointer(dumb_ptr const &p)
+ {
+ return p.p;
+ }
+
+ T *p;
+};
+
+struct U : dumb_ptr<U>
+{
+ U() : dumb_ptr<U>(this), x(42) {}
+ int x;
+};
+
+my_terminal<U *dumb_ptr<U>::*> U_p = {{&U::p}};
+my_terminal<int U::*> U_x = {{&U::x}};
+
+void potentially_ambiguous_transform()
+{
+ U u;
+
+ // This should yield a non-const reference to a pointer-to-const
+ U *&up = evaluator()(U_p(u));
+ BOOST_CHECK_EQUAL(&up, &u.p);
+
+ // This should yield a non-const reference to a pointer-to-const
+ int &ux = evaluator()(U_x(u));
+ BOOST_CHECK_EQUAL(&ux, &u.x);
+}
+
+
+using namespace boost::unit_test;
+///////////////////////////////////////////////////////////////////////////////
+// init_unit_test_suite
+//
+test_suite* init_unit_test_suite( int argc, char* argv[] )
+{
+ test_suite *test = BOOST_TEST_SUITE("test handling of member pointers by the default transform and default contexts");
+
+ test->add(BOOST_TEST_CASE(&test_refs_transform));
+ test->add(BOOST_TEST_CASE(&test_refs_context));
+
+ test->add(BOOST_TEST_CASE(&test_ptrs_transform));
+ test->add(BOOST_TEST_CASE(&test_ptrs_context));
+
+ test->add(BOOST_TEST_CASE(&with_get_pointer_transform));
+
+ test->add(BOOST_TEST_CASE(&potentially_ambiguous_transform));
+
+ return test;
+}


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk