1 ///////////////////////////////////////////////////////////////////////////////
4 // Copyright 2009 Eric Niebler. Distributed under the Boost
5 // Software License, Version 1.0. (See accompanying file
6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 #include <boost/mpl/print.hpp>
10 #include <boost/shared_ptr.hpp>
11 #include <boost/proto/proto.hpp>
12 #include <boost/mpl/assert.hpp>
13 #include <boost/type_traits/is_same.hpp>
14 #include <boost/utility/result_of.hpp>
15 #include <boost/test/unit_test.hpp>
17 namespace proto
= boost::proto
;
21 : proto::when
<_
, proto::_default
<evaluator
> >
24 template<typename Ret
, typename Expr
>
25 void assert_result_type(Expr
&)
27 // check that the return type as calculated by the _default transform
32 , typename
boost::result_of
<evaluator(Expr
&)>::type
36 // check that the return type as calculated by the default_context
41 , typename
boost::result_of
<proto::functional::eval(Expr
&, proto::default_context
&)>::type
46 ///////////////////////////////////////////////////////////////////////////////
53 // like a normal terminal except with an operator() that can
54 // accept non-const lvalues (Proto's only accepts const lvalues)
55 template<typename T
, typename Dummy
= proto::is_proto_expr
>
58 typedef typename
proto::terminal
<T
>::type my_terminal_base
;
59 BOOST_PROTO_BASIC_EXTENDS(my_terminal_base
, my_terminal
, proto::default_domain
)
62 typename
proto::result_of::make_expr
<proto::tag::function
, my_terminal
const &, A0
&>::type
const
63 operator()(A0
&a0
) const
65 return proto::make_expr
<proto::tag::function
>(boost::ref(*this), boost::ref(a0
));
69 typename
proto::result_of::make_expr
<proto::tag::function
, my_terminal
const &, A0
const &>::type
const
70 operator()(A0
const &a0
) const
72 return proto::make_expr
<proto::tag::function
>(boost::ref(*this), boost::ref(a0
));
76 my_terminal
<int S::*> test1
= {{ &S::x
}};
78 // Some tests with the default transform
79 void test_refs_transform()
82 BOOST_REQUIRE_EQUAL(s
.x
, -42);
84 // Check that evaluating a memptr invocation with a
85 // non-const lvalue argument yields the member as a
87 assert_result_type
<int &>(test1(s
));
88 evaluator()(test1(s
)) = 0;
89 BOOST_CHECK_EQUAL(s
.x
, 0);
91 // Ditto for reference_wrappers
92 assert_result_type
<int &>(test1(boost::ref(s
)));
93 evaluator()(test1(boost::ref(s
))) = 42;
94 BOOST_CHECK_EQUAL(s
.x
, 42);
96 // Check that evaluating a memptr invocation with a
97 // const lvalue argument yields the member as a
100 assert_result_type
<int const &>(test1(rcs
));
101 int const &s_x
= evaluator()(test1(rcs
));
102 BOOST_CHECK_EQUAL(&s
.x
, &s_x
);
105 // Some tests with the default context
106 void test_refs_context()
108 proto::default_context ctx
;
110 BOOST_REQUIRE_EQUAL(s
.x
, -42);
112 // Check that evaluating a memptr invocation with a
113 // non-const lvalue argument yields the member as a
115 assert_result_type
<int &>(test1(s
));
116 proto::eval(test1(s
), ctx
) = 0;
117 BOOST_CHECK_EQUAL(s
.x
, 0);
119 // Ditto for reference_wrappers
120 assert_result_type
<int &>(test1(boost::ref(s
)));
121 proto::eval(test1(boost::ref(s
)), ctx
) = 42;
122 BOOST_CHECK_EQUAL(s
.x
, 42);
124 // Check that evaluating a memptr invocation with a
125 // const lvalue argument yields the member as a
128 assert_result_type
<int const &>(test1(rcs
));
129 int const &s_x
= proto::eval(test1(rcs
), ctx
);
130 BOOST_CHECK_EQUAL(&s
.x
, &s_x
);
133 void test_ptrs_transform()
136 BOOST_REQUIRE_EQUAL(s
.x
, -42);
138 // Check that evaluating a memptr invocation with a
139 // pointer to a non-const argument yields the member as a
141 assert_result_type
<int &>(test1(&s
));
142 evaluator()(test1(&s
)) = 0;
143 BOOST_CHECK_EQUAL(s
.x
, 0);
146 assert_result_type
<int &>(test1(ps
));
147 evaluator()(test1(ps
)) = 42;
148 BOOST_CHECK_EQUAL(s
.x
, 42);
150 boost::shared_ptr
<S
> const sp(new S
);
151 BOOST_REQUIRE_EQUAL(sp
->x
, -42);
153 // Ditto for shared_ptr (which hook the get_pointer()
154 // customization point)
155 assert_result_type
<int &>(test1(sp
));
156 evaluator()(test1(sp
)) = 0;
157 BOOST_CHECK_EQUAL(sp
->x
, 0);
159 // Check that evaluating a memptr invocation with a
160 // const lvalue argument yields the member as a
163 assert_result_type
<int const &>(test1(&rcs
));
164 int const &s_x0
= evaluator()(test1(&rcs
));
165 BOOST_CHECK_EQUAL(&s
.x
, &s_x0
);
168 assert_result_type
<int const &>(test1(pcs
));
169 int const &s_x1
= evaluator()(test1(pcs
));
170 BOOST_CHECK_EQUAL(&s
.x
, &s_x1
);
172 boost::shared_ptr
<S
const> spc(new S
);
173 BOOST_REQUIRE_EQUAL(spc
->x
, -42);
175 assert_result_type
<int const &>(test1(spc
));
176 int const &s_x2
= evaluator()(test1(spc
));
177 BOOST_CHECK_EQUAL(&spc
->x
, &s_x2
);
180 void test_ptrs_context()
182 proto::default_context ctx
;
184 BOOST_REQUIRE_EQUAL(s
.x
, -42);
186 // Check that evaluating a memptr invocation with a
187 // pointer to a non-const argument yields the member as a
189 assert_result_type
<int &>(test1(&s
));
190 proto::eval(test1(&s
), ctx
) = 0;
191 BOOST_CHECK_EQUAL(s
.x
, 0);
194 assert_result_type
<int &>(test1(ps
));
195 proto::eval(test1(ps
), ctx
) = 42;
196 BOOST_CHECK_EQUAL(s
.x
, 42);
198 boost::shared_ptr
<S
> const sp(new S
);
199 BOOST_REQUIRE_EQUAL(sp
->x
, -42);
201 // Ditto for shared_ptr (which hook the get_pointer()
202 // customization point)
203 assert_result_type
<int &>(test1(sp
));
204 proto::eval(test1(sp
), ctx
) = 0;
205 BOOST_CHECK_EQUAL(sp
->x
, 0);
207 // Check that evaluating a memptr invocation with a
208 // const lvalue argument yields the member as a
211 assert_result_type
<int const &>(test1(&rcs
));
212 int const &s_x0
= proto::eval(test1(&rcs
), ctx
);
213 BOOST_CHECK_EQUAL(&s
.x
, &s_x0
);
216 assert_result_type
<int const &>(test1(pcs
));
217 int const &s_x1
= proto::eval(test1(pcs
), ctx
);
218 BOOST_CHECK_EQUAL(&s
.x
, &s_x1
);
220 boost::shared_ptr
<S
const> spc(new S
);
221 BOOST_REQUIRE_EQUAL(spc
->x
, -42);
223 assert_result_type
<int const &>(test1(spc
));
224 int const &s_x2
= proto::eval(test1(spc
), ctx
);
225 BOOST_CHECK_EQUAL(&spc
->x
, &s_x2
);
228 ///////////////////////////////////////////////////////////////////////////////
234 proto::terminal
<int T::*>::type test2
= { &T::x
};
236 int const *get_pointer(T
const &t
)
241 void with_get_pointer_transform()
244 evaluator()(test2(t
));
247 ///////////////////////////////////////////////////////////////////////////////
251 dumb_ptr(T
*p_
) : p(p_
) {}
253 friend T
const *get_pointer(dumb_ptr
const &p
)
261 struct U
: dumb_ptr
<U
>
263 U() : dumb_ptr
<U
>(this), x(42) {}
267 my_terminal
<U
*dumb_ptr
<U
>::*> U_p
= {{&U::p
}};
268 my_terminal
<int U::*> U_x
= {{&U::x
}};
270 void potentially_ambiguous_transform()
274 // This should yield a non-const reference to a pointer-to-const
275 U
*&up
= evaluator()(U_p(u
));
276 BOOST_CHECK_EQUAL(&up
, &u
.p
);
278 // This should yield a non-const reference to a pointer-to-const
279 int &ux
= evaluator()(U_x(u
));
280 BOOST_CHECK_EQUAL(&ux
, &u
.x
);
284 using namespace boost::unit_test
;
285 ///////////////////////////////////////////////////////////////////////////////
286 // init_unit_test_suite
288 test_suite
* init_unit_test_suite( int argc
, char* argv
[] )
290 test_suite
*test
= BOOST_TEST_SUITE("test handling of member pointers by the default transform and default contexts");
292 test
->add(BOOST_TEST_CASE(&test_refs_transform
));
293 test
->add(BOOST_TEST_CASE(&test_refs_context
));
295 test
->add(BOOST_TEST_CASE(&test_ptrs_transform
));
296 test
->add(BOOST_TEST_CASE(&test_ptrs_context
));
298 test
->add(BOOST_TEST_CASE(&with_get_pointer_transform
));
300 test
->add(BOOST_TEST_CASE(&potentially_ambiguous_transform
));