123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- ///////////////////////////////////////////////////////////////////////////////
- // 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::ref(*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::ref(*this), boost::ref(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;
- }
|