]>
Commit | Line | Data |
---|---|---|
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> | |
201 | T &lvalue(T &t) | |
202 | { | |
203 | return t; | |
204 | } | |
205 | ||
206 | template<typename T> | |
207 | T const &lvalue(T const &t) | |
208 | { | |
209 | return t; | |
210 | } | |
211 | ||
212 | //////////////////////////////////////////////////////////////////////////////////////////// | |
213 | template<typename U, typename V, typename T> | |
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> | |
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> | |
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 | |
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 | |
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 | ||
314 | 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_( | |
334 | 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 | ||
427 | memfun(T t, pmf_type p) | |
428 | : obj(t) | |
429 | , pmf(p) | |
430 | {} | |
431 | ||
432 | 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 |