1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2012-2015.
4 // Distributed under the Boost Software License, Version 1.0.
5 // (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // See http://www.boost.org/libs/move for documentation.
9 //
10 //////////////////////////////////////////////////////////////////////////////
11
12 //! \file
13
14 #ifndef BOOST_MOVE_DETAIL_META_UTILS_HPP
15 #define BOOST_MOVE_DETAIL_META_UTILS_HPP
16
17 #if defined(BOOST_HAS_PRAGMA_ONCE)
18 # pragma once
19 #endif
20 #include <boost/move/detail/config_begin.hpp>
21 #include <boost/move/detail/workaround.hpp> //forceinline
22 #include <boost/move/detail/meta_utils_core.hpp>
23 #include <cstddef> //for std::size_t
24
25 //Small meta-typetraits to support move
26
27 namespace boost {
28
29 //Forward declare boost::rv
30 template <class T> class rv;
31
32 namespace move_detail {
33
34 //////////////////////////////////////
35 // is_different
36 //////////////////////////////////////
37 template<class T, class U>
38 struct is_different
39 {
40 static const bool value = !is_same<T, U>::value;
41 };
42
43 //////////////////////////////////////
44 // apply
45 //////////////////////////////////////
46 template<class F, class Param>
47 struct apply
48 {
49 typedef typename F::template apply<Param>::type type;
50 };
51
52 //////////////////////////////////////
53 // bool_
54 //////////////////////////////////////
55
56 template< bool C_ >
57 struct bool_ : integral_constant<bool, C_>
58 {
operator boolboost::move_detail::bool_59 operator bool() const { return C_; }
operator ()boost::move_detail::bool_60 bool operator()() const { return C_; }
61 };
62
63 typedef bool_<true> true_;
64 typedef bool_<false> false_;
65
66 //////////////////////////////////////
67 // nat
68 //////////////////////////////////////
69 struct nat{};
70 struct nat2{};
71 struct nat3{};
72
73 //////////////////////////////////////
74 // yes_type/no_type
75 //////////////////////////////////////
76 typedef char yes_type;
77
78 struct no_type
79 {
80 char _[2];
81 };
82
83 //////////////////////////////////////
84 // natify
85 //////////////////////////////////////
86 template <class T> struct natify{};
87
88 //////////////////////////////////////
89 // remove_reference
90 //////////////////////////////////////
91 template<class T>
92 struct remove_reference
93 {
94 typedef T type;
95 };
96
97 template<class T>
98 struct remove_reference<T&>
99 {
100 typedef T type;
101 };
102
103 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
104
105 template<class T>
106 struct remove_reference<T&&>
107 {
108 typedef T type;
109 };
110
111 #else
112
113 template<class T>
114 struct remove_reference< rv<T> >
115 {
116 typedef T type;
117 };
118
119 template<class T>
120 struct remove_reference< rv<T> &>
121 {
122 typedef T type;
123 };
124
125 template<class T>
126 struct remove_reference< const rv<T> &>
127 {
128 typedef T type;
129 };
130
131 #endif
132
133 //////////////////////////////////////
134 // remove_pointer
135 //////////////////////////////////////
136
137 template< class T > struct remove_pointer { typedef T type; };
138 template< class T > struct remove_pointer<T*> { typedef T type; };
139 template< class T > struct remove_pointer<T* const> { typedef T type; };
140 template< class T > struct remove_pointer<T* volatile> { typedef T type; };
141 template< class T > struct remove_pointer<T* const volatile> { typedef T type; };
142
143 //////////////////////////////////////
144 // add_pointer
145 //////////////////////////////////////
146 template< class T >
147 struct add_pointer
148 {
149 typedef typename remove_reference<T>::type* type;
150 };
151
152 //////////////////////////////////////
153 // add_const
154 //////////////////////////////////////
155 template<class T>
156 struct add_const
157 {
158 typedef const T type;
159 };
160
161 template<class T>
162 struct add_const<T&>
163 {
164 typedef const T& type;
165 };
166
167 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
168
169 template<class T>
170 struct add_const<T&&>
171 {
172 typedef T&& type;
173 };
174
175 #endif
176
177 //////////////////////////////////////
178 // add_lvalue_reference
179 //////////////////////////////////////
180 template<class T>
181 struct add_lvalue_reference
182 { typedef T& type; };
183
184 template<class T> struct add_lvalue_reference<T&> { typedef T& type; };
185 template<> struct add_lvalue_reference<void> { typedef void type; };
186 template<> struct add_lvalue_reference<const void> { typedef const void type; };
187 template<> struct add_lvalue_reference<volatile void> { typedef volatile void type; };
188 template<> struct add_lvalue_reference<const volatile void>{ typedef const volatile void type; };
189
190 template<class T>
191 struct add_const_lvalue_reference
192 {
193 typedef typename remove_reference<T>::type t_unreferenced;
194 typedef typename add_const<t_unreferenced>::type t_unreferenced_const;
195 typedef typename add_lvalue_reference
196 <t_unreferenced_const>::type type;
197 };
198
199 //////////////////////////////////////
200 // is_lvalue_reference
201 //////////////////////////////////////
202 template<class T>
203 struct is_lvalue_reference
204 {
205 static const bool value = false;
206 };
207
208 template<class T>
209 struct is_lvalue_reference<T&>
210 {
211 static const bool value = true;
212 };
213
214
215 //////////////////////////////////////
216 // identity
217 //////////////////////////////////////
218 template <class T>
219 struct identity
220 {
221 typedef T type;
222 typedef typename add_const_lvalue_reference<T>::type reference;
operator ()boost::move_detail::identity223 reference operator()(reference t)
224 { return t; }
225 };
226
227 //////////////////////////////////////
228 // is_class_or_union
229 //////////////////////////////////////
230 template<class T>
231 struct is_class_or_union
232 {
233 struct twochar { char dummy[2]; };
234 template <class U>
235 static char is_class_or_union_tester(void(U::*)(void));
236 template <class U>
237 static twochar is_class_or_union_tester(...);
238 static const bool value = sizeof(is_class_or_union_tester<T>(0)) == sizeof(char);
239 };
240
241 //////////////////////////////////////
242 // addressof
243 //////////////////////////////////////
244 template<class T>
245 struct addr_impl_ref
246 {
247 T & v_;
addr_impl_refboost::move_detail::addr_impl_ref248 BOOST_MOVE_FORCEINLINE addr_impl_ref( T & v ): v_( v ) {}
operator T&boost::move_detail::addr_impl_ref249 BOOST_MOVE_FORCEINLINE operator T& () const { return v_; }
250
251 private:
252 addr_impl_ref & operator=(const addr_impl_ref &);
253 };
254
255 template<class T>
256 struct addressof_impl
257 {
fboost::move_detail::addressof_impl258 BOOST_MOVE_FORCEINLINE static T * f( T & v, long )
259 {
260 return reinterpret_cast<T*>(
261 &const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
262 }
263
fboost::move_detail::addressof_impl264 BOOST_MOVE_FORCEINLINE static T * f( T * v, int )
265 { return v; }
266 };
267
268 template<class T>
addressof(T & v)269 BOOST_MOVE_FORCEINLINE T * addressof( T & v )
270 {
271 return ::boost::move_detail::addressof_impl<T>::f
272 ( ::boost::move_detail::addr_impl_ref<T>( v ), 0 );
273 }
274
275 //////////////////////////////////////
276 // has_pointer_type
277 //////////////////////////////////////
278 template <class T>
279 struct has_pointer_type
280 {
281 struct two { char c[2]; };
282 template <class U> static two test(...);
283 template <class U> static char test(typename U::pointer* = 0);
284 static const bool value = sizeof(test<T>(0)) == 1;
285 };
286
287 //////////////////////////////////////
288 // is_convertible
289 //////////////////////////////////////
290 #if defined(_MSC_VER) && (_MSC_VER >= 1400)
291
292 //use intrinsic since in MSVC
293 //overaligned types can't go through ellipsis
294 template <class T, class U>
295 struct is_convertible
296 {
297 static const bool value = __is_convertible_to(T, U);
298 };
299
300 #else
301
302 template <class T, class U>
303 class is_convertible
304 {
305 typedef typename add_lvalue_reference<T>::type t_reference;
306 typedef char true_t;
307 class false_t { char dummy[2]; };
308 static false_t dispatch(...);
309 static true_t dispatch(U);
310 static t_reference trigger();
311 public:
312 static const bool value = sizeof(dispatch(trigger())) == sizeof(true_t);
313 };
314
315 #endif
316
317 template <class T, class U, bool IsSame = is_same<T, U>::value>
318 struct is_same_or_convertible
319 : is_convertible<T, U>
320 {};
321
322 template <class T, class U>
323 struct is_same_or_convertible<T, U, true>
324 {
325 static const bool value = true;
326 };
327
328 template<
329 bool C
330 , typename F1
331 , typename F2
332 >
333 struct eval_if_c
334 : if_c<C,F1,F2>::type
335 {};
336
337 template<
338 typename C
339 , typename T1
340 , typename T2
341 >
342 struct eval_if
343 : if_<C,T1,T2>::type
344 {};
345
346
347 #if defined(BOOST_GCC) && (BOOST_GCC <= 40000)
348 #define BOOST_MOVE_HELPERS_RETURN_SFINAE_BROKEN
349 #endif
350
351 template<class T, class U, class R = void>
352 struct enable_if_convertible
353 : enable_if< is_convertible<T, U>, R>
354 {};
355
356 template<class T, class U, class R = void>
357 struct disable_if_convertible
358 : disable_if< is_convertible<T, U>, R>
359 {};
360
361 template<class T, class U, class R = void>
362 struct enable_if_same_or_convertible
363 : enable_if< is_same_or_convertible<T, U>, R>
364 {};
365
366 template<class T, class U, class R = void>
367 struct disable_if_same_or_convertible
368 : disable_if< is_same_or_convertible<T, U>, R>
369 {};
370
371 //////////////////////////////////////////////////////////////////////////////
372 //
373 // and_
374 //
375 //////////////////////////////////////////////////////////////////////////////
376 template<bool, class B = true_, class C = true_, class D = true_>
377 struct and_impl
378 : and_impl<B::value, C, D>
379 {};
380
381 template<>
382 struct and_impl<true, true_, true_, true_>
383 {
384 static const bool value = true;
385 };
386
387 template<class B, class C, class D>
388 struct and_impl<false, B, C, D>
389 {
390 static const bool value = false;
391 };
392
393 template<class A, class B, class C = true_, class D = true_>
394 struct and_
395 : and_impl<A::value, B, C, D>
396 {};
397
398 //////////////////////////////////////////////////////////////////////////////
399 //
400 // or_
401 //
402 //////////////////////////////////////////////////////////////////////////////
403 template<bool, class B = false_, class C = false_, class D = false_>
404 struct or_impl
405 : or_impl<B::value, C, D>
406 {};
407
408 template<>
409 struct or_impl<false, false_, false_, false_>
410 {
411 static const bool value = false;
412 };
413
414 template<class B, class C, class D>
415 struct or_impl<true, B, C, D>
416 {
417 static const bool value = true;
418 };
419
420 template<class A, class B, class C = false_, class D = false_>
421 struct or_
422 : or_impl<A::value, B, C, D>
423 {};
424
425 //////////////////////////////////////////////////////////////////////////////
426 //
427 // not_
428 //
429 //////////////////////////////////////////////////////////////////////////////
430 template<class T>
431 struct not_
432 {
433 static const bool value = !T::value;
434 };
435
436 //////////////////////////////////////////////////////////////////////////////
437 //
438 // enable_if_and / disable_if_and / enable_if_or / disable_if_or
439 //
440 //////////////////////////////////////////////////////////////////////////////
441
442 template<class R, class A, class B, class C = true_, class D = true_>
443 struct enable_if_and
444 : enable_if_c< and_<A, B, C, D>::value, R>
445 {};
446
447 template<class R, class A, class B, class C = true_, class D = true_>
448 struct disable_if_and
449 : disable_if_c< and_<A, B, C, D>::value, R>
450 {};
451
452 template<class R, class A, class B, class C = false_, class D = false_>
453 struct enable_if_or
454 : enable_if_c< or_<A, B, C, D>::value, R>
455 {};
456
457 template<class R, class A, class B, class C = false_, class D = false_>
458 struct disable_if_or
459 : disable_if_c< or_<A, B, C, D>::value, R>
460 {};
461
462 //////////////////////////////////////////////////////////////////////////////
463 //
464 // has_move_emulation_enabled_impl
465 //
466 //////////////////////////////////////////////////////////////////////////////
467 template<class T>
468 struct has_move_emulation_enabled_impl
469 : is_convertible< T, ::boost::rv<T>& >
470 {};
471
472 template<class T>
473 struct has_move_emulation_enabled_impl<T&>
474 { static const bool value = false; };
475
476 template<class T>
477 struct has_move_emulation_enabled_impl< ::boost::rv<T> >
478 { static const bool value = false; };
479
480 //////////////////////////////////////////////////////////////////////////////
481 //
482 // is_rv_impl
483 //
484 //////////////////////////////////////////////////////////////////////////////
485
486 template <class T>
487 struct is_rv_impl
488 { static const bool value = false; };
489
490 template <class T>
491 struct is_rv_impl< rv<T> >
492 { static const bool value = true; };
493
494 template <class T>
495 struct is_rv_impl< const rv<T> >
496 { static const bool value = true; };
497
498 // Code from Jeffrey Lee Hellrung, many thanks
499
500 template< class T >
501 struct is_rvalue_reference
502 { static const bool value = false; };
503
504 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
505
506 template< class T >
507 struct is_rvalue_reference< T&& >
508 { static const bool value = true; };
509
510 #else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
511
512 template< class T >
513 struct is_rvalue_reference< boost::rv<T>& >
514 { static const bool value = true; };
515
516 template< class T >
517 struct is_rvalue_reference< const boost::rv<T>& >
518 { static const bool value = true; };
519
520 #endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
521
522 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
523
524 template< class T >
525 struct add_rvalue_reference
526 { typedef T&& type; };
527
528 #else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
529
530 namespace detail_add_rvalue_reference
531 {
532 template< class T
533 , bool emulation = has_move_emulation_enabled_impl<T>::value
534 , bool rv = is_rv_impl<T>::value >
535 struct add_rvalue_reference_impl { typedef T type; };
536
537 template< class T, bool emulation>
538 struct add_rvalue_reference_impl< T, emulation, true > { typedef T & type; };
539
540 template< class T, bool rv >
541 struct add_rvalue_reference_impl< T, true, rv > { typedef ::boost::rv<T>& type; };
542 } // namespace detail_add_rvalue_reference
543
544 template< class T >
545 struct add_rvalue_reference
546 : detail_add_rvalue_reference::add_rvalue_reference_impl<T>
547 { };
548
549 template< class T >
550 struct add_rvalue_reference<T &>
551 { typedef T & type; };
552
553 #endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
554
555 template< class T > struct remove_rvalue_reference { typedef T type; };
556
557 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
558 template< class T > struct remove_rvalue_reference< T&& > { typedef T type; };
559 #else // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
560 template< class T > struct remove_rvalue_reference< rv<T> > { typedef T type; };
561 template< class T > struct remove_rvalue_reference< const rv<T> > { typedef T type; };
562 template< class T > struct remove_rvalue_reference< volatile rv<T> > { typedef T type; };
563 template< class T > struct remove_rvalue_reference< const volatile rv<T> > { typedef T type; };
564 template< class T > struct remove_rvalue_reference< rv<T>& > { typedef T type; };
565 template< class T > struct remove_rvalue_reference< const rv<T>& > { typedef T type; };
566 template< class T > struct remove_rvalue_reference< volatile rv<T>& > { typedef T type; };
567 template< class T > struct remove_rvalue_reference< const volatile rv<T>& >{ typedef T type; };
568 #endif // #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
569
570 // Ideas from Boost.Move review, Jeffrey Lee Hellrung:
571 //
572 //- TypeTraits metafunctions is_lvalue_reference, add_lvalue_reference, and remove_lvalue_reference ?
573 // Perhaps add_reference and remove_reference can be modified so that they behave wrt emulated rvalue
574 // references the same as wrt real rvalue references, i.e., add_reference< rv<T>& > -> T& rather than
575 // rv<T>& (since T&& & -> T&).
576 //
577 //- Add'l TypeTraits has_[trivial_]move_{constructor,assign}...?
578 //
579 //- An as_lvalue(T& x) function, which amounts to an identity operation in C++0x, but strips emulated
580 // rvalue references in C++03. This may be necessary to prevent "accidental moves".
581
582 } //namespace move_detail {
583 } //namespace boost {
584
585 #include <boost/move/detail/config_end.hpp>
586
587 #endif //#ifndef BOOST_MOVE_DETAIL_META_UTILS_HPP
588