1 ///////////////////////////////////////////////////////////////////////////////
2 /// \file decltype.hpp
3 /// Contains definition the BOOST_PROTO_DECLTYPE_() macro and assorted helpers
4 //
5 //  Copyright 2008 Eric Niebler. Distributed under the Boost
6 //  Software License, Version 1.0. (See accompanying file
7 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 
9 #ifndef BOOST_PROTO_DETAIL_DECLTYPE_HPP_EAN_04_04_2008
10 #define BOOST_PROTO_DETAIL_DECLTYPE_HPP_EAN_04_04_2008
11 
12 #include <boost/config.hpp>
13 #include <boost/detail/workaround.hpp>
14 #include <boost/get_pointer.hpp>
15 #include <boost/preprocessor/cat.hpp>
16 #include <boost/preprocessor/repetition/enum_params.hpp>
17 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
18 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
19 #include <boost/preprocessor/repetition/repeat.hpp>
20 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
21 #include <boost/preprocessor/iteration/local.hpp>
22 #include <boost/mpl/if.hpp>
23 #include <boost/mpl/eval_if.hpp>
24 #include <boost/mpl/identity.hpp>
25 #include <boost/type_traits/is_class.hpp>
26 #include <boost/type_traits/remove_reference.hpp>
27 #include <boost/type_traits/is_pointer.hpp>
28 #include <boost/type_traits/is_function.hpp>
29 #include <boost/type_traits/is_member_object_pointer.hpp>
30 #include <boost/type_traits/add_const.hpp>
31 #include <boost/type_traits/add_reference.hpp>
32 #include <boost/typeof/typeof.hpp>
33 #include <boost/utility/addressof.hpp>
34 #include <boost/utility/result_of.hpp>
35 #include <boost/utility/enable_if.hpp>
36 #include <boost/proto/proto_fwd.hpp>
37 #include <boost/proto/detail/any.hpp>
38 
39 #if defined(_MSC_VER)
40 # pragma warning(push)
41 # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined
42 #endif
43 
44 // We're STILL using Boost.Typeof on MSVC even for msvc-11.0 because of this bug:
45 // https://connect.microsoft.com/VisualStudio/feedback/details/765392/decltype-of-a-pointer-to-member-operator-gets-ref-qualification-wrong
46 #if !defined(BOOST_NO_CXX11_DECLTYPE) && !BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1700))
47 # define BOOST_PROTO_DECLTYPE_(EXPR, TYPE) typedef decltype((EXPR)) TYPE;
48 #else
49 # define BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_(NESTED, EXPR)                                     \
50     BOOST_TYPEOF_NESTED_TYPEDEF_TPL(BOOST_PP_CAT(nested_and_hidden_, NESTED), EXPR)                 \
51     static int const BOOST_PP_CAT(sz, NESTED) = sizeof(boost::proto::detail::check_reference(EXPR));\
52     struct NESTED                                                                                   \
53       : boost::mpl::if_c<                                                                           \
54             1 == BOOST_PP_CAT(sz, NESTED)                                                           \
55           , typename BOOST_PP_CAT(nested_and_hidden_, NESTED)::type &                               \
56           , typename BOOST_PP_CAT(nested_and_hidden_, NESTED)::type                                 \
57         >                                                                                           \
58     {};
59 # define BOOST_PROTO_DECLTYPE_(EXPR, TYPE)                                                          \
60     BOOST_PROTO_DECLTYPE_NESTED_TYPEDEF_TPL_(BOOST_PP_CAT(nested_, TYPE), (EXPR))                   \
61     typedef typename BOOST_PP_CAT(nested_, TYPE)::type TYPE;
62 #endif
63 
64 namespace boost { namespace proto
65 {
66     namespace detail
67     {
68         ////////////////////////////////////////////////////////////////////////////////////////////
69         template<typename T>
70         struct as_mutable
71         {
72             typedef T &type;
73         };
74 
75         template<typename T>
76         struct as_mutable<T &>
77         {
78             typedef T &type;
79         };
80 
81         template<typename T>
82         struct as_mutable<T const &>
83         {
84             typedef T &type;
85         };
86 
87         ////////////////////////////////////////////////////////////////////////////////////////////
88         template<typename T>
89         T make();
90 
91         ////////////////////////////////////////////////////////////////////////////////////////////
92         template<typename T>
93         typename as_mutable<T>::type make_mutable();
94 
95         ////////////////////////////////////////////////////////////////////////////////////////////
96         template<typename T>
97         struct subscript_wrapper
98           : T
99         {
100             using T::operator[];
101 
102             #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1500))
103             any operator[](any const volatile &) const volatile;
104             #else
105             any operator[](any const &) const volatile;
106             #endif
107         };
108 
109         ////////////////////////////////////////////////////////////////////////////////////////////
110         template<typename T>
111         struct as_subscriptable
112         {
113             typedef
114                 typename mpl::if_c<
115                     is_class<T>::value
116                   , subscript_wrapper<T>
117                   , T
118                 >::type
119             type;
120         };
121 
122         template<typename T>
123         struct as_subscriptable<T const>
124         {
125             typedef
126                 typename mpl::if_c<
127                     is_class<T>::value
128                   , subscript_wrapper<T> const
129                   , T const
130                 >::type
131             type;
132         };
133 
134         template<typename T>
135         struct as_subscriptable<T &>
136         {
137             typedef
138                 typename mpl::if_c<
139                     is_class<T>::value
140                   , subscript_wrapper<T> &
141                   , T &
142                 >::type
143             type;
144         };
145 
146         template<typename T>
147         struct as_subscriptable<T const &>
148         {
149             typedef
150                 typename mpl::if_c<
151                     is_class<T>::value
152                   , subscript_wrapper<T> const &
153                   , T const &
154                 >::type
155             type;
156         };
157 
158         ////////////////////////////////////////////////////////////////////////////////////////////
159         template<typename T>
160         typename as_subscriptable<T>::type make_subscriptable();
161 
162         ////////////////////////////////////////////////////////////////////////////////////////////
163         template<typename T>
164         char check_reference(T &);
165 
166         template<typename T>
167         char (&check_reference(T const &))[2];
168 
169         namespace has_get_pointerns
170         {
171             using boost::get_pointer;
172             void *(&get_pointer(...))[2];
173 
174             ////////////////////////////////////////////////////////////////////////////////////////////
175             template<typename T>
176             struct has_get_pointer
177             {
178                 static const bool value = sizeof(void *) == sizeof(get_pointer(make<T &>()));
179                 typedef mpl::bool_<value> type;
180             };
181         }
182 
183         using has_get_pointerns::has_get_pointer;
184 
185         ////////////////////////////////////////////////////////////////////////////////////////////
186         template<typename T>
187         struct class_member_traits;
188 
189         template<typename T, typename U>
190         struct class_member_traits<T U::*>
191         {
192             typedef U class_type;
193             typedef T result_type;
194         };
195 
196         // Other specializations are generated by the preprocessor
197         #include <boost/proto/detail/class_member_traits.hpp>
198 
199         ////////////////////////////////////////////////////////////////////////////////////////////
200         template<typename T>
lvalue(T & t)201         T &lvalue(T &t)
202         {
203             return t;
204         }
205 
206         template<typename T>
lvalue(T const & t)207         T const &lvalue(T const &t)
208         {
209             return t;
210         }
211 
212         ////////////////////////////////////////////////////////////////////////////////////////////
213         template<typename U, typename V, typename T>
proto_get_pointer(T & t,V *,U *)214         U *proto_get_pointer(T &t, V *, U *)
215         {
216             return boost::addressof(t);
217         }
218 
219         template<typename U, typename V, typename T>
proto_get_pointer(T & t,V *,U const *)220         U const *proto_get_pointer(T &t, V *, U const *)
221         {
222             return boost::addressof(t);
223         }
224 
225         template<typename U, typename V, typename T>
proto_get_pointer(T & t,V *,...)226         V *proto_get_pointer(T &t, V *, ...)
227         {
228             return get_pointer(t);
229         }
230 
231         ////////////////////////////////////////////////////////////////////////////////////////////
232         #define BOOST_PROTO_USE_GET_POINTER()                                                       \
233         using namespace boost::proto::detail::get_pointerns                                         \
234         /**/
235 
236         #define BOOST_PROTO_GET_POINTER(Type, Obj)                                                  \
237         boost::proto::detail::proto_get_pointer<Type>(                                              \
238             boost::proto::detail::lvalue(Obj)                                                       \
239           , (true ? 0 : get_pointer(Obj))                                                           \
240           , (true ? 0 : boost::addressof(boost::proto::detail::lvalue(Obj)))                        \
241         )                                                                                           \
242         /**/
243 
244         ////////////////////////////////////////////////////////////////////////////////////////////
245         namespace get_pointerns
246         {
247             using boost::get_pointer;
248 
249             template<typename T>
250             typename disable_if_c<has_get_pointer<T>::value, T *>::type
get_pointer(T & t)251             get_pointer(T &t)
252             {
253                 return boost::addressof(t);
254             }
255 
256             template<typename T>
257             typename disable_if_c<has_get_pointer<T>::value, T const *>::type
get_pointer(T const & t)258             get_pointer(T const &t)
259             {
260                 return boost::addressof(t);
261             }
262 
263             char test_ptr_to_const(void *);
264             char (&test_ptr_to_const(void const *))[2];
265 
266             template<typename U> char test_V_is_a_U(U *);
267             template<typename U> char test_V_is_a_U(U const *);
268             template<typename U> char (&test_V_is_a_U(...))[2];
269 
270             ////////////////////////////////////////////////////////////////////////////////////////////
271             // result_of_ is a wrapper around boost::result_of that also handles "invocations" of
272             // member object pointers.
273             template<typename T, typename Void = void>
274             struct result_of_
275               : BOOST_PROTO_RESULT_OF<T>
276             {};
277 
278             template<typename T, typename U, typename V>
279             struct result_of_<T U::*(V), typename enable_if_c<is_member_object_pointer<T U::*>::value>::type>
280             {
281                 static const bool is_V_a_smart_ptr = 2 == sizeof(test_V_is_a_U<U>(&lvalue(make<V>())));
282                 static const bool is_ptr_to_const = 2 == sizeof(test_ptr_to_const(BOOST_PROTO_GET_POINTER(U, make<V>())));
283 
284                 // If V is not a U, then it is a (smart) pointer and we can always return an lvalue.
285                 // Otherwise, we can only return an lvalue if we are given one.
286                 typedef
287                     typename mpl::eval_if_c<
288                         (is_V_a_smart_ptr || is_reference<V>::value)
289                       , mpl::eval_if_c<
290                             is_ptr_to_const
291                           , add_reference<typename add_const<T>::type>
292                           , add_reference<T>
293                         >
294                       , mpl::identity<T>
295                     >::type
296                 type;
297             };
298 
299             ////////////////////////////////////////////////////////////////////////////////////////////
300             template<
301                 typename T
302               , typename U
303               , bool IsMemPtr = is_member_object_pointer<
304                     typename remove_reference<U>::type
305                 >::value
306             >
307             struct mem_ptr_fun
308             {
309                 BOOST_PROTO_DECLTYPE_(
310                     proto::detail::make_mutable<T>() ->* proto::detail::make<U>()
311                   , result_type
312                 )
313 
operator ()boost::proto::detail::get_pointerns::mem_ptr_fun314                 result_type operator()(
315                     typename add_reference<typename add_const<T>::type>::type t
316                   , typename add_reference<typename add_const<U>::type>::type u
317                 ) const
318                 {
319                     return t ->* u;
320                 }
321             };
322 
323             ////////////////////////////////////////////////////////////////////////////////////////////
324             template<typename T, typename U>
325             struct mem_ptr_fun<T, U, true>
326             {
327                 typedef
328                     typename class_member_traits<
329                         typename uncvref<U>::type
330                     >::class_type
331                 V;
332 
333                 BOOST_PROTO_DECLTYPE_(
BOOST_PROTO_GET_POINTERboost::proto::detail::get_pointerns::mem_ptr_fun334                     BOOST_PROTO_GET_POINTER(V, proto::detail::make_mutable<T>()) ->* proto::detail::make<U>()
335                   , result_type
336                 )
337 
338                 result_type operator()(
339                     typename add_reference<typename add_const<T>::type>::type t
340                   , U u
341                 ) const
342                 {
343                     return BOOST_PROTO_GET_POINTER(V, t) ->* u;
344                 }
345             };
346         }
347 
348         using get_pointerns::result_of_;
349         using get_pointerns::mem_ptr_fun;
350 
351         ////////////////////////////////////////////////////////////////////////////////////////////
352         template<typename A0, typename A1>
353         struct comma_result
354         {
355             BOOST_PROTO_DECLTYPE_((proto::detail::make<A0>(), proto::detail::make<A1>()), type)
356         };
357 
358         template<typename A0>
359         struct comma_result<A0, void>
360         {
361             typedef void type;
362         };
363 
364         template<typename A1>
365         struct comma_result<void, A1>
366         {
367             typedef A1 type;
368         };
369 
370         template<>
371         struct comma_result<void, void>
372         {
373             typedef void type;
374         };
375 
376         ////////////////////////////////////////////////////////////////////////////////////////////
377         // normalize a function type for use with boost::result_of
378         template<typename T, typename U = T>
379         struct result_of_fixup
380           : mpl::if_c<is_function<T>::value, T *, U>
381         {};
382 
383         template<typename T, typename U>
384         struct result_of_fixup<T &, U>
385           : result_of_fixup<T, T>
386         {};
387 
388         template<typename T, typename U>
389         struct result_of_fixup<T const &, U>
390           : result_of_fixup<T, T>
391         {};
392 
393         template<typename T, typename U>
394         struct result_of_fixup<T *, U>
395           : result_of_fixup<T, U>
396         {};
397 
398         template<typename R, typename T, typename U>
399         struct result_of_fixup<R T::*, U>
400         {
401             typedef R T::*type;
402         };
403 
404         template<typename T, typename U>
405         struct result_of_fixup<T const, U>
406           : result_of_fixup<T, U>
407         {};
408 
409         //// Tests for result_of_fixup
410         //struct bar {};
411         //BOOST_MPL_ASSERT((is_same<bar,        result_of_fixup<bar>::type>));
412         //BOOST_MPL_ASSERT((is_same<bar const,  result_of_fixup<bar const>::type>));
413         //BOOST_MPL_ASSERT((is_same<bar,        result_of_fixup<bar &>::type>));
414         //BOOST_MPL_ASSERT((is_same<bar const,  result_of_fixup<bar const &>::type>));
415         //BOOST_MPL_ASSERT((is_same<void(*)(),  result_of_fixup<void(*)()>::type>));
416         //BOOST_MPL_ASSERT((is_same<void(*)(),  result_of_fixup<void(* const)()>::type>));
417         //BOOST_MPL_ASSERT((is_same<void(*)(),  result_of_fixup<void(* const &)()>::type>));
418         //BOOST_MPL_ASSERT((is_same<void(*)(),  result_of_fixup<void(&)()>::type>));
419 
420         template<typename T, typename PMF>
421         struct memfun
422         {
423             typedef typename uncvref<PMF>::type pmf_type;
424             typedef typename class_member_traits<pmf_type>::class_type V;
425             typedef typename class_member_traits<pmf_type>::result_type result_type;
426 
memfunboost::proto::detail::memfun427             memfun(T t, pmf_type p)
428               : obj(t)
429               , pmf(p)
430             {}
431 
operator ()boost::proto::detail::memfun432             result_type operator()() const
433             {
434                 BOOST_PROTO_USE_GET_POINTER();
435                 return (BOOST_PROTO_GET_POINTER(V, obj) ->* pmf)();
436             }
437 
438             // Other overloads generated by the preprocessor
439             #include <boost/proto/detail/memfun_funop.hpp>
440 
441         private:
442             T obj;
443             pmf_type pmf;
444         };
445 
446     } // namespace detail
447 }}
448 
449 #if defined(_MSC_VER)
450 # pragma warning(pop)
451 #endif
452 
453 #endif
454