1 //----------------------------------------------------------------------------- |
1 //----------------------------------------------------------------------------- |
2 // boost variant/variant.hpp header file |
2 // boost variant.hpp header file |
3 // See http://www.boost.org for updates, documentation, and revision history. |
3 // See http://www.boost.org for updates, documentation, and revision history. |
4 //----------------------------------------------------------------------------- |
4 //----------------------------------------------------------------------------- |
5 // |
5 // |
6 // Copyright (c) 2002-2003 |
6 // Copyright (c) 2003 |
7 // Eric Friedman, Itay Maman |
7 // Eric Friedman, Itay Maman |
8 // |
8 // |
9 // Distributed under the Boost Software License, Version 1.0. (See |
9 // Distributed under the Boost Software License, Version 1.0. (See |
10 // accompanying file LICENSE_1_0.txt or copy at |
10 // accompanying file LICENSE_1_0.txt or copy at |
11 // http://www.boost.org/LICENSE_1_0.txt) |
11 // http://www.boost.org/LICENSE_1_0.txt) |
12 /* |
|
13 * © Portions copyright (c) 2006-2007 Nokia Corporation. All rights reserved. |
|
14 */ |
|
15 #ifndef BOOST_VARIANT_VARIANT_HPP |
|
16 #define BOOST_VARIANT_VARIANT_HPP |
|
17 |
12 |
18 #include <cstddef> // for std::size_t |
13 #ifndef BOOST_VARIANT_HPP |
19 #include <new> // for placement new |
14 #define BOOST_VARIANT_HPP |
20 #ifdef __SYMBIAN32__ |
|
21 #include <string> |
|
22 #endif |
|
23 #include <typeinfo> // for typeid, std::type_info |
|
24 |
15 |
25 #include "boost/variant/detail/config.hpp" |
16 // variant "main" |
26 #include "boost/mpl/aux_/config/eti.hpp" |
17 #include "boost/variant/variant.hpp" |
27 #include "boost/mpl/aux_/value_wknd.hpp" |
18 #include "boost/variant/recursive_variant.hpp" |
|
19 #include "boost/variant/recursive_wrapper.hpp" |
28 |
20 |
29 #include "boost/variant/variant_fwd.hpp" |
21 // common applications |
30 #include "boost/variant/detail/backup_holder.hpp" |
22 #include "boost/variant/get.hpp" |
31 #include "boost/variant/detail/enable_recursive_fwd.hpp" |
23 #include "boost/variant/apply_visitor.hpp" |
32 #include "boost/variant/detail/forced_return.hpp" |
24 #include "boost/variant/static_visitor.hpp" |
33 #include "boost/variant/detail/initializer.hpp" |
25 #include "boost/variant/visitor_ptr.hpp" |
34 #include "boost/variant/detail/make_variant_list.hpp" |
|
35 #include "boost/variant/detail/over_sequence.hpp" |
|
36 #include "boost/variant/detail/visitation_impl.hpp" |
|
37 |
26 |
38 #include "boost/variant/detail/generic_result_type.hpp" |
27 #endif // BOOST_VARIANT_HPP |
39 #include "boost/variant/detail/has_nothrow_move.hpp" |
|
40 #include "boost/variant/detail/move.hpp" |
|
41 |
|
42 #include "boost/detail/reference_content.hpp" |
|
43 #include "boost/aligned_storage.hpp" |
|
44 #include "boost/blank.hpp" |
|
45 #include "boost/static_assert.hpp" |
|
46 #include "boost/preprocessor/cat.hpp" |
|
47 #include "boost/preprocessor/repeat.hpp" |
|
48 #include "boost/type_traits/alignment_of.hpp" |
|
49 #include "boost/type_traits/add_const.hpp" |
|
50 #include "boost/type_traits/has_nothrow_constructor.hpp" |
|
51 #include "boost/type_traits/has_nothrow_copy.hpp" |
|
52 #include "boost/type_traits/is_const.hpp" |
|
53 #include "boost/type_traits/is_same.hpp" |
|
54 #include "boost/utility/enable_if.hpp" |
|
55 #include "boost/variant/recursive_wrapper_fwd.hpp" |
|
56 #include "boost/variant/static_visitor.hpp" |
|
57 |
|
58 #include "boost/mpl/eval_if.hpp" |
|
59 #include "boost/mpl/begin_end.hpp" |
|
60 #include "boost/mpl/bool.hpp" |
|
61 #include "boost/mpl/empty.hpp" |
|
62 #include "boost/mpl/find_if.hpp" |
|
63 #include "boost/mpl/front.hpp" |
|
64 #include "boost/mpl/identity.hpp" |
|
65 #include "boost/mpl/if.hpp" |
|
66 #include "boost/mpl/int.hpp" |
|
67 #include "boost/mpl/is_sequence.hpp" |
|
68 #include "boost/mpl/iterator_range.hpp" |
|
69 #include "boost/mpl/iter_fold_if.hpp" |
|
70 #include "boost/mpl/logical.hpp" |
|
71 #include "boost/mpl/max_element.hpp" |
|
72 #include "boost/mpl/next.hpp" |
|
73 #include "boost/mpl/deref.hpp" |
|
74 #include "boost/mpl/pair.hpp" |
|
75 #include "boost/mpl/protect.hpp" |
|
76 #include "boost/mpl/push_front.hpp" |
|
77 #include "boost/mpl/same_as.hpp" |
|
78 #include "boost/mpl/size_t.hpp" |
|
79 #include "boost/mpl/sizeof.hpp" |
|
80 #include "boost/mpl/transform.hpp" |
|
81 #include "boost/mpl/assert.hpp" |
|
82 |
|
83 /////////////////////////////////////////////////////////////////////////////// |
|
84 // Implementation Macros: |
|
85 // |
|
86 // BOOST_VARIANT_VISITATION_UNROLLING_LIMIT |
|
87 // Defined in boost/variant/detail/visitation_impl.hpp. |
|
88 // |
|
89 // BOOST_VARIANT_MINIMIZE_SIZE |
|
90 // When #defined, implementation employs all known means to minimize the |
|
91 // size of variant obje cts. However, often unsuccessful due to alignment |
|
92 // issues, and potentially harmful to runtime speed, so not enabled by |
|
93 // default. (TODO: Investigate further.) |
|
94 |
|
95 #if defined(BOOST_VARIANT_MINIMIZE_SIZE) |
|
96 # include <climits> // for SCHAR_MAX |
|
97 # include "boost/mpl/eval_if.hpp" |
|
98 # include "boost/mpl/equal_to.hpp" |
|
99 # include "boost/mpl/identity.hpp" |
|
100 # include "boost/mpl/int.hpp" |
|
101 # include "boost/mpl/if.hpp" |
|
102 # include "boost/mpl/less.hpp" |
|
103 # include "boost/mpl/long.hpp" |
|
104 # include "boost/mpl/O1_size.hpp" |
|
105 #endif |
|
106 |
|
107 |
|
108 namespace boost { |
|
109 |
|
110 namespace detail { namespace variant { |
|
111 |
|
112 /////////////////////////////////////////////////////////////////////////////// |
|
113 // (detail) metafunction max_value |
|
114 // |
|
115 // Finds the maximum value of the unary metafunction F over Sequence. |
|
116 // |
|
117 template <typename Sequence, typename F> |
|
118 struct max_value |
|
119 { |
|
120 private: // helpers, for metafunction result (below) |
|
121 |
|
122 typedef typename mpl::transform1<Sequence, F>::type transformed_; |
|
123 typedef typename mpl::max_element<transformed_ |
|
124 |
|
125 >::type max_it; |
|
126 |
|
127 public: // metafunction result |
|
128 |
|
129 typedef typename mpl::deref<max_it>::type |
|
130 type; |
|
131 |
|
132 }; |
|
133 |
|
134 /////////////////////////////////////////////////////////////////////////////// |
|
135 // (detail) metafunction find_fallback_type |
|
136 // |
|
137 // Provides a fallback (i.e., nothrow default-constructible) type from the |
|
138 // specified sequence, or no_fallback_type if not found. |
|
139 // |
|
140 // This implementation is designed to prefer boost::blank over other potential |
|
141 // fallback types, regardless of its position in the specified sequence. |
|
142 // |
|
143 |
|
144 class no_fallback_type; |
|
145 |
|
146 struct find_fallback_type_pred |
|
147 { |
|
148 template <typename Iterator> |
|
149 struct apply |
|
150 { |
|
151 private: |
|
152 typedef typename mpl::deref<Iterator>::type t_; |
|
153 |
|
154 public: |
|
155 typedef mpl::not_< has_nothrow_constructor<t_> > type; |
|
156 }; |
|
157 }; |
|
158 |
|
159 template <typename Types> |
|
160 struct find_fallback_type |
|
161 { |
|
162 private: // helpers, for metafunction result (below) |
|
163 |
|
164 typedef typename mpl::end<Types>::type end_it; |
|
165 |
|
166 // [Find the first suitable fallback type...] |
|
167 |
|
168 typedef typename mpl::iter_fold_if< |
|
169 Types |
|
170 , mpl::int_<0>, mpl::protect< mpl::next<> > |
|
171 , mpl::protect< find_fallback_type_pred > |
|
172 >::type first_result_; |
|
173 |
|
174 typedef typename first_result_::first first_result_index; |
|
175 typedef typename first_result_::second first_result_it; |
|
176 |
|
177 // [...now search the rest of the sequence for boost::blank...] |
|
178 |
|
179 typedef typename mpl::iter_fold_if< |
|
180 mpl::iterator_range< first_result_it,end_it > |
|
181 , first_result_index, mpl::protect< mpl::next<> > |
|
182 , mpl::protect< mpl::not_same_as<boost::blank> > |
|
183 >::type second_result_; |
|
184 |
|
185 typedef typename second_result_::second second_result_it; |
|
186 |
|
187 public: // metafunction result |
|
188 |
|
189 // [...and return the results of the search:] |
|
190 typedef typename mpl::eval_if< |
|
191 is_same< second_result_it,end_it > |
|
192 , mpl::if_< |
|
193 is_same< first_result_it,end_it > |
|
194 , mpl::pair< no_fallback_type,no_fallback_type > |
|
195 , first_result_ |
|
196 > |
|
197 , mpl::identity< second_result_ > |
|
198 >::type type; |
|
199 |
|
200 }; |
|
201 |
|
202 #if defined(BOOST_MPL_CFG_MSVC_60_ETI_BUG) |
|
203 |
|
204 template<> |
|
205 struct find_fallback_type<int> |
|
206 { |
|
207 typedef mpl::pair< no_fallback_type,no_fallback_type > type; |
|
208 }; |
|
209 |
|
210 #endif // BOOST_MPL_CFG_MSVC_60_ETI_BUG workaround |
|
211 |
|
212 /////////////////////////////////////////////////////////////////////////////// |
|
213 // (detail) metafunction make_storage |
|
214 // |
|
215 // Provides an aligned storage type capable of holding any of the types |
|
216 // specified in the given type-sequence. |
|
217 // |
|
218 |
|
219 template <typename Types, typename NeverUsesBackupFlag> |
|
220 struct make_storage |
|
221 { |
|
222 private: // helpers, for metafunction result (below) |
|
223 |
|
224 typedef typename mpl::eval_if< |
|
225 NeverUsesBackupFlag |
|
226 , mpl::identity< Types > |
|
227 , mpl::push_front< |
|
228 Types, backup_holder<void*> |
|
229 > |
|
230 >::type types; |
|
231 |
|
232 typedef typename max_value< |
|
233 types, mpl::sizeof_<mpl::_1> |
|
234 >::type max_size; |
|
235 |
|
236 #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551)) |
|
237 |
|
238 typedef typename max_value< |
|
239 types, alignment_of<mpl::_1> |
|
240 >::type max_alignment; |
|
241 |
|
242 #else // borland |
|
243 |
|
244 // temporary workaround -- use maximal alignment |
|
245 typedef mpl::size_t< -1 > max_alignment; |
|
246 |
|
247 #endif // borland workaround |
|
248 |
|
249 public: // metafunction result |
|
250 |
|
251 #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) |
|
252 |
|
253 typedef ::boost::aligned_storage< |
|
254 BOOST_MPL_AUX_VALUE_WKND(max_size)::value |
|
255 , BOOST_MPL_AUX_VALUE_WKND(max_alignment)::value |
|
256 > type; |
|
257 |
|
258 #else // MSVC7 and below |
|
259 |
|
260 BOOST_STATIC_CONSTANT(std::size_t, msvc_max_size_c = max_size::value); |
|
261 BOOST_STATIC_CONSTANT(std::size_t, msvc_max_alignment_c = max_alignment::value); |
|
262 |
|
263 typedef ::boost::aligned_storage< |
|
264 msvc_max_size_c |
|
265 , msvc_max_alignment_c |
|
266 > type; |
|
267 |
|
268 #endif // MSVC workaround |
|
269 |
|
270 }; |
|
271 |
|
272 #if defined(BOOST_MPL_CFG_MSVC_60_ETI_BUG) |
|
273 |
|
274 template<> |
|
275 struct make_storage<int,int> |
|
276 { |
|
277 typedef int type; |
|
278 }; |
|
279 |
|
280 #endif // BOOST_MPL_CFG_MSVC_60_ETI_BUG workaround |
|
281 |
|
282 /////////////////////////////////////////////////////////////////////////////// |
|
283 // (detail) class destroyer |
|
284 // |
|
285 // Internal visitor that destroys the value it visits. |
|
286 // |
|
287 struct destroyer |
|
288 : public static_visitor<> |
|
289 { |
|
290 public: // visitor interfaces |
|
291 |
|
292 template <typename T> |
|
293 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
294 internal_visit(T& operand, int) const |
|
295 { |
|
296 operand.~T(); |
|
297 |
|
298 #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551)) |
|
299 operand; // suppresses warnings |
|
300 #endif |
|
301 |
|
302 BOOST_VARIANT_AUX_RETURN_VOID; |
|
303 } |
|
304 |
|
305 }; |
|
306 |
|
307 /////////////////////////////////////////////////////////////////////////////// |
|
308 // (detail) class template known_get |
|
309 // |
|
310 // Visitor that returns a reference to content of the specified type. |
|
311 // |
|
312 // Precondition: visited variant MUST contain logical content of type T. |
|
313 // |
|
314 template <typename T> |
|
315 class known_get |
|
316 : public static_visitor<T&> |
|
317 { |
|
318 |
|
319 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) |
|
320 |
|
321 public: // visitor interface |
|
322 |
|
323 T& operator()(T& operand) const |
|
324 { |
|
325 return operand; |
|
326 } |
|
327 |
|
328 template <typename U> |
|
329 T& operator()(U&) const |
|
330 { |
|
331 // logical error to be here: see precondition above |
|
332 BOOST_ASSERT(false); |
|
333 return ::boost::detail::variant::forced_return< T& >(); |
|
334 } |
|
335 |
|
336 #else // MSVC6 |
|
337 |
|
338 private: // helpers, for visitor interface (below) |
|
339 |
|
340 T& execute(T& operand, mpl::true_) const |
|
341 { |
|
342 return operand; |
|
343 } |
|
344 |
|
345 template <typename U> |
|
346 T& execute(U& operand, mpl::false_) const |
|
347 { |
|
348 // logical error to be here: see precondition above |
|
349 BOOST_ASSERT(false); |
|
350 return ::boost::detail::variant::forced_return< T& >(); |
|
351 } |
|
352 |
|
353 public: // visitor interface |
|
354 |
|
355 template <typename U> |
|
356 T& operator()(U& operand) const |
|
357 { |
|
358 typedef typename is_same< U,T >::type |
|
359 U_is_T; |
|
360 |
|
361 return execute(operand, U_is_T()); |
|
362 } |
|
363 |
|
364 #endif // MSVC6 workaround |
|
365 |
|
366 }; |
|
367 |
|
368 /////////////////////////////////////////////////////////////////////////////// |
|
369 // (detail) class copy_into |
|
370 // |
|
371 // Internal visitor that copies the value it visits into the given buffer. |
|
372 // |
|
373 class copy_into |
|
374 : public static_visitor<> |
|
375 { |
|
376 private: // representation |
|
377 |
|
378 void* storage_; |
|
379 |
|
380 public: // structors |
|
381 |
|
382 explicit copy_into(void* storage) |
|
383 : storage_(storage) |
|
384 { |
|
385 } |
|
386 |
|
387 public: // internal visitor interface |
|
388 |
|
389 template <typename T> |
|
390 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
391 internal_visit(boost::detail::variant::backup_holder<T>& operand, long) const |
|
392 { |
|
393 new(storage_) T( operand.get() ); |
|
394 BOOST_VARIANT_AUX_RETURN_VOID; |
|
395 } |
|
396 |
|
397 template <typename T> |
|
398 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
399 internal_visit(const boost::detail::variant::backup_holder<T>& operand, long) const |
|
400 { |
|
401 new(storage_) T( operand.get() ); |
|
402 BOOST_VARIANT_AUX_RETURN_VOID; |
|
403 } |
|
404 |
|
405 template <typename T> |
|
406 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
407 internal_visit(const T& operand, int) const |
|
408 { |
|
409 new(storage_) T(operand); |
|
410 BOOST_VARIANT_AUX_RETURN_VOID; |
|
411 } |
|
412 |
|
413 }; |
|
414 |
|
415 /////////////////////////////////////////////////////////////////////////////// |
|
416 // (detail) class assign_storage |
|
417 // |
|
418 // Internal visitor that assigns the given storage (which must be a |
|
419 // constructed value of the same type) to the value it visits. |
|
420 // |
|
421 struct assign_storage |
|
422 : public static_visitor<> |
|
423 { |
|
424 private: // representation |
|
425 |
|
426 const void* rhs_storage_; |
|
427 |
|
428 public: // structors |
|
429 |
|
430 explicit assign_storage(const void* rhs_storage) |
|
431 : rhs_storage_(rhs_storage) |
|
432 { |
|
433 } |
|
434 |
|
435 public: // internal visitor interfaces |
|
436 |
|
437 template <typename T> |
|
438 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
439 internal_visit(backup_holder<T>& lhs_content, long) const |
|
440 { |
|
441 lhs_content.get() |
|
442 = static_cast< const backup_holder<T>* >(rhs_storage_)->get(); |
|
443 BOOST_VARIANT_AUX_RETURN_VOID; |
|
444 } |
|
445 |
|
446 template <typename T> |
|
447 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
448 internal_visit(const backup_holder<T>& lhs_content, long) const |
|
449 { |
|
450 lhs_content.get() |
|
451 = static_cast< const backup_holder<T>* >(rhs_storage_)->get(); |
|
452 BOOST_VARIANT_AUX_RETURN_VOID; |
|
453 } |
|
454 |
|
455 template <typename T> |
|
456 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
457 internal_visit(T& lhs_content, int) const |
|
458 { |
|
459 // NOTE TO USER : |
|
460 // Compile error here indicates one of variant's bounded types does |
|
461 // not meet the requirements of the Assignable concept. Thus, |
|
462 // variant is not Assignable. |
|
463 // |
|
464 // Hint: Are any of the bounded types const-qualified or references? |
|
465 // |
|
466 lhs_content = *static_cast< const T* >(rhs_storage_); |
|
467 BOOST_VARIANT_AUX_RETURN_VOID; |
|
468 } |
|
469 |
|
470 }; |
|
471 |
|
472 /////////////////////////////////////////////////////////////////////////////// |
|
473 // (detail) class direct_assigner |
|
474 // |
|
475 // Generic static visitor that: if and only if the visited value is of the |
|
476 // specified type, assigns the given value to the visited value and returns |
|
477 // true; else returns false. |
|
478 // |
|
479 template <typename T> |
|
480 class direct_assigner |
|
481 : public static_visitor<bool> |
|
482 { |
|
483 private: // representation |
|
484 |
|
485 T& rhs_; |
|
486 |
|
487 public: // structors |
|
488 |
|
489 explicit direct_assigner(T& rhs) |
|
490 : rhs_(rhs) |
|
491 { |
|
492 } |
|
493 |
|
494 #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) |
|
495 |
|
496 public: // visitor interface |
|
497 |
|
498 bool operator()(T& lhs) |
|
499 { |
|
500 lhs = rhs_; |
|
501 return true; |
|
502 } |
|
503 |
|
504 template <typename U> |
|
505 bool operator()(U&) |
|
506 { |
|
507 return false; |
|
508 } |
|
509 |
|
510 #else // MSVC6 |
|
511 |
|
512 private: // helpers, for visitor interface (below) |
|
513 |
|
514 bool execute(T& lhs, mpl::true_) |
|
515 { |
|
516 lhs = rhs_; |
|
517 return true; |
|
518 } |
|
519 |
|
520 template <typename U> |
|
521 bool execute(U&, mpl::false_) |
|
522 { |
|
523 return false; |
|
524 } |
|
525 |
|
526 public: // visitor interface |
|
527 |
|
528 template <typename U> |
|
529 bool operator()(U& lhs) |
|
530 { |
|
531 typedef typename is_same<U,T>::type U_is_T; |
|
532 return execute(lhs, U_is_T()); |
|
533 } |
|
534 |
|
535 #endif // MSVC6 workaround |
|
536 |
|
537 }; |
|
538 |
|
539 /////////////////////////////////////////////////////////////////////////////// |
|
540 // (detail) class backup_assigner |
|
541 // |
|
542 // Internal visitor that "assigns" the given value to the visited value, |
|
543 // using backup to recover if the destroy-copy sequence fails. |
|
544 // |
|
545 // NOTE: This needs to be a friend of variant, as it needs access to |
|
546 // indicate_which, indicate_backup_which, etc. |
|
547 // |
|
548 template <typename Variant, typename RhsT> |
|
549 class backup_assigner |
|
550 : public static_visitor<> |
|
551 { |
|
552 private: // representation |
|
553 |
|
554 Variant& lhs_; |
|
555 int rhs_which_; |
|
556 const RhsT& rhs_content_; |
|
557 |
|
558 public: // structors |
|
559 |
|
560 backup_assigner(Variant& lhs, int rhs_which, const RhsT& rhs_content) |
|
561 : lhs_(lhs) |
|
562 , rhs_which_(rhs_which) |
|
563 , rhs_content_(rhs_content) |
|
564 { |
|
565 } |
|
566 |
|
567 private: // helpers, for visitor interface (below) |
|
568 |
|
569 template <typename LhsT> |
|
570 void backup_assign_impl( |
|
571 LhsT& lhs_content |
|
572 , mpl::true_// has_nothrow_move |
|
573 ) |
|
574 { |
|
575 // Move lhs content to backup... |
|
576 LhsT backup_lhs_content( |
|
577 ::boost::detail::variant::move(lhs_content) |
|
578 ); // nothrow |
|
579 |
|
580 // ...destroy lhs content... |
|
581 lhs_content.~LhsT(); // nothrow |
|
582 |
|
583 try |
|
584 { |
|
585 // ...and attempt to copy rhs content into lhs storage: |
|
586 new(lhs_.storage_.address()) RhsT(rhs_content_); |
|
587 } |
|
588 catch (...) |
|
589 { |
|
590 // In case of failure, restore backup content to lhs storage... |
|
591 new(lhs_.storage_.address()) |
|
592 LhsT( |
|
593 ::boost::detail::variant::move(backup_lhs_content) |
|
594 ); // nothrow |
|
595 |
|
596 // ...and rethrow: |
|
597 throw; |
|
598 } |
|
599 |
|
600 // In case of success, indicate new content type: |
|
601 lhs_.indicate_which(rhs_which_); // nothrow |
|
602 } |
|
603 |
|
604 template <typename LhsT> |
|
605 void backup_assign_impl( |
|
606 LhsT& lhs_content |
|
607 , mpl::false_// has_nothrow_move |
|
608 ) |
|
609 { |
|
610 // Backup lhs content... |
|
611 LhsT* backup_lhs_ptr = new LhsT(lhs_content); |
|
612 |
|
613 // ...destroy lhs content... |
|
614 lhs_content.~LhsT(); // nothrow |
|
615 |
|
616 try |
|
617 { |
|
618 // ...and attempt to copy rhs content into lhs storage: |
|
619 new(lhs_.storage_.address()) RhsT(rhs_content_); |
|
620 } |
|
621 catch (...) |
|
622 { |
|
623 // In case of failure, copy backup pointer to lhs storage... |
|
624 new(lhs_.storage_.address()) |
|
625 backup_holder<LhsT>( backup_lhs_ptr ); // nothrow |
|
626 |
|
627 // ...indicate now using backup... |
|
628 lhs_.indicate_backup_which( lhs_.which() ); // nothrow |
|
629 |
|
630 // ...and rethrow: |
|
631 throw; |
|
632 } |
|
633 |
|
634 // In case of success, indicate new content type... |
|
635 lhs_.indicate_which(rhs_which_); // nothrow |
|
636 |
|
637 // ...and delete backup: |
|
638 delete backup_lhs_ptr; // nothrow |
|
639 } |
|
640 |
|
641 public: // visitor interface |
|
642 |
|
643 template <typename LhsT> |
|
644 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
645 internal_visit(LhsT& lhs_content, int) |
|
646 { |
|
647 typedef typename has_nothrow_move_constructor<LhsT>::type |
|
648 nothrow_move; |
|
649 |
|
650 backup_assign_impl( lhs_content, nothrow_move() ); |
|
651 |
|
652 BOOST_VARIANT_AUX_RETURN_VOID; |
|
653 } |
|
654 |
|
655 }; |
|
656 |
|
657 /////////////////////////////////////////////////////////////////////////////// |
|
658 // (detail) class swap_with |
|
659 // |
|
660 // Visitor that swaps visited value with content of given variant. |
|
661 // |
|
662 // Precondition: Given variant MUST have same logical type as visited value. |
|
663 // |
|
664 template <typename Variant> |
|
665 struct swap_with |
|
666 : public static_visitor<> |
|
667 { |
|
668 private: // representation |
|
669 |
|
670 Variant& toswap_; |
|
671 |
|
672 public: // structors |
|
673 |
|
674 explicit swap_with(Variant& toswap) |
|
675 : toswap_(toswap) |
|
676 { |
|
677 } |
|
678 |
|
679 public: // internal visitor interfaces |
|
680 |
|
681 template <typename T> |
|
682 void operator()(T& operand) const |
|
683 { |
|
684 // Since the precondition ensures types are same, get T... |
|
685 known_get<T> getter; |
|
686 T& other = toswap_.apply_visitor(getter); |
|
687 |
|
688 // ...and swap: |
|
689 ::boost::detail::variant::move_swap( operand, other ); |
|
690 } |
|
691 |
|
692 }; |
|
693 |
|
694 /////////////////////////////////////////////////////////////////////////////// |
|
695 // (detail) class reflect |
|
696 // |
|
697 // Generic static visitor that performs a typeid on the value it visits. |
|
698 // |
|
699 class reflect |
|
700 : public static_visitor<const std::type_info&> |
|
701 { |
|
702 public: // visitor interfaces |
|
703 |
|
704 template <typename T> |
|
705 const std::type_info& operator()(const T&) const |
|
706 { |
|
707 return typeid(T); |
|
708 } |
|
709 |
|
710 }; |
|
711 |
|
712 /////////////////////////////////////////////////////////////////////////////// |
|
713 // (detail) class comparer |
|
714 // |
|
715 // Generic static visitor that compares the content of the given lhs variant |
|
716 // with the visited rhs content using Comp. |
|
717 // |
|
718 // Precondition: lhs.which() == rhs.which() |
|
719 // |
|
720 template <typename Variant, typename Comp> |
|
721 class comparer |
|
722 : public static_visitor<bool> |
|
723 { |
|
724 private: // representation |
|
725 |
|
726 const Variant& lhs_; |
|
727 |
|
728 public: // structors |
|
729 |
|
730 explicit comparer(const Variant& lhs) |
|
731 : lhs_(lhs) |
|
732 { |
|
733 } |
|
734 |
|
735 public: // visitor interfaces |
|
736 |
|
737 template <typename T> |
|
738 bool operator()(const T& rhs_content) const |
|
739 { |
|
740 // Since the precondition ensures lhs and rhs types are same, get T... |
|
741 known_get<const T> getter; |
|
742 const T& lhs_content = lhs_.apply_visitor(getter); |
|
743 |
|
744 // ...and compare lhs and rhs contents: |
|
745 return Comp()(lhs_content, rhs_content); |
|
746 } |
|
747 |
|
748 }; |
|
749 |
|
750 /////////////////////////////////////////////////////////////////////////////// |
|
751 // (detail) class equal_comp |
|
752 // |
|
753 // Generic function object compares lhs with rhs using operator==. |
|
754 // |
|
755 struct equal_comp |
|
756 { |
|
757 template <typename T> |
|
758 bool operator()(const T& lhs, const T& rhs) const |
|
759 { |
|
760 return lhs == rhs; |
|
761 } |
|
762 }; |
|
763 |
|
764 /////////////////////////////////////////////////////////////////////////////// |
|
765 // (detail) class less_comp |
|
766 // |
|
767 // Generic function object compares lhs with rhs using operator<. |
|
768 // |
|
769 struct less_comp |
|
770 { |
|
771 template <typename T> |
|
772 bool operator()(const T& lhs, const T& rhs) const |
|
773 { |
|
774 return lhs < rhs; |
|
775 } |
|
776 }; |
|
777 |
|
778 /////////////////////////////////////////////////////////////////////////////// |
|
779 // (detail) class template invoke_visitor |
|
780 // |
|
781 // Internal visitor that invokes the given visitor using: |
|
782 // * for wrappers (e.g., recursive_wrapper), the wrapper's held value. |
|
783 // * for all other values, the value itself. |
|
784 // |
|
785 template <typename Visitor> |
|
786 class invoke_visitor |
|
787 { |
|
788 private: // representation |
|
789 |
|
790 Visitor& visitor_; |
|
791 |
|
792 public: // visitor typedefs |
|
793 |
|
794 typedef typename Visitor::result_type |
|
795 result_type; |
|
796 |
|
797 public: // structors |
|
798 |
|
799 explicit invoke_visitor(Visitor& visitor) |
|
800 : visitor_(visitor) |
|
801 { |
|
802 } |
|
803 |
|
804 #if !defined(BOOST_NO_VOID_RETURNS) |
|
805 |
|
806 public: // internal visitor interfaces |
|
807 |
|
808 template <typename T> |
|
809 result_type internal_visit(T& operand, int) |
|
810 { |
|
811 return visitor_(operand); |
|
812 } |
|
813 |
|
814 # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) |
|
815 template <typename T> |
|
816 result_type internal_visit(const T& operand, int) |
|
817 { |
|
818 return visitor_(operand); |
|
819 } |
|
820 # endif |
|
821 |
|
822 #else // defined(BOOST_NO_VOID_RETURNS) |
|
823 |
|
824 private: // helpers, for internal visitor interfaces (below) |
|
825 |
|
826 template <typename T> |
|
827 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) |
|
828 visit_impl(T& operand, mpl::false_) |
|
829 { |
|
830 return visitor_(operand); |
|
831 } |
|
832 |
|
833 template <typename T> |
|
834 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
835 visit_impl(T& operand, mpl::true_) |
|
836 { |
|
837 visitor_(operand); |
|
838 BOOST_VARIANT_AUX_RETURN_VOID; |
|
839 } |
|
840 |
|
841 public: // internal visitor interfaces |
|
842 |
|
843 template <typename T> |
|
844 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) |
|
845 internal_visit(T& operand, int) |
|
846 { |
|
847 typedef typename is_same<result_type, void>::type |
|
848 has_void_result_type; |
|
849 |
|
850 return visit_impl(operand, has_void_result_type()); |
|
851 } |
|
852 |
|
853 #endif // BOOST_NO_VOID_RETURNS) workaround |
|
854 |
|
855 public: // internal visitor interfaces, cont. |
|
856 |
|
857 template <typename T> |
|
858 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) |
|
859 internal_visit(boost::recursive_wrapper<T>& operand, long) |
|
860 { |
|
861 return internal_visit( operand.get(), 1L ); |
|
862 } |
|
863 |
|
864 template <typename T> |
|
865 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) |
|
866 internal_visit(const boost::recursive_wrapper<T>& operand, long) |
|
867 { |
|
868 return internal_visit( operand.get(), 1L ); |
|
869 } |
|
870 |
|
871 template <typename T> |
|
872 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) |
|
873 internal_visit(boost::detail::reference_content<T>& operand, long) |
|
874 { |
|
875 return internal_visit( operand.get(), 1L ); |
|
876 } |
|
877 |
|
878 template <typename T> |
|
879 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) |
|
880 internal_visit(const boost::detail::reference_content<T>& operand, long) |
|
881 { |
|
882 return internal_visit( operand.get(), 1L ); |
|
883 } |
|
884 |
|
885 template <typename T> |
|
886 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) |
|
887 internal_visit(boost::detail::variant::backup_holder<T>& operand, long) |
|
888 { |
|
889 return internal_visit( operand.get(), 1L ); |
|
890 } |
|
891 |
|
892 template <typename T> |
|
893 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) |
|
894 internal_visit(const boost::detail::variant::backup_holder<T>& operand, long) |
|
895 { |
|
896 return internal_visit( operand.get(), 1L ); |
|
897 } |
|
898 |
|
899 }; |
|
900 |
|
901 }} // namespace detail::variant |
|
902 |
|
903 /////////////////////////////////////////////////////////////////////////////// |
|
904 // class template variant (concept inspired by Andrei Alexandrescu) |
|
905 // |
|
906 // See docs and boost/variant/variant_fwd.hpp for more information. |
|
907 // |
|
908 template < |
|
909 typename T0_ |
|
910 , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename T) |
|
911 > |
|
912 class variant |
|
913 { |
|
914 private: // helpers, for typedefs (below) |
|
915 |
|
916 typedef variant wknd_self_t; |
|
917 |
|
918 struct is_recursive_ |
|
919 : detail::variant::is_recursive_flag<T0_> |
|
920 { |
|
921 }; |
|
922 |
|
923 typedef typename mpl::eval_if< |
|
924 is_recursive_ |
|
925 , T0_ |
|
926 , mpl::identity< T0_ > |
|
927 >::type unwrapped_T0_; |
|
928 |
|
929 struct is_sequence_based_ |
|
930 : detail::variant::is_over_sequence<unwrapped_T0_> |
|
931 { |
|
932 }; |
|
933 |
|
934 #if !defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) |
|
935 |
|
936 private: // helpers, for typedefs (below) |
|
937 |
|
938 typedef typename mpl::eval_if< |
|
939 is_sequence_based_ |
|
940 , unwrapped_T0_ // over_sequence<...>::type |
|
941 , detail::variant::make_variant_list< |
|
942 unwrapped_T0_ |
|
943 , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T) |
|
944 > |
|
945 >::type specified_types; |
|
946 |
|
947 BOOST_STATIC_ASSERT(( |
|
948 ::boost::mpl::not_< mpl::empty<specified_types> >::value |
|
949 )); |
|
950 |
|
951 typedef typename mpl::eval_if< |
|
952 is_recursive_ |
|
953 , mpl::transform< |
|
954 specified_types |
|
955 , mpl::protect< |
|
956 detail::variant::quoted_enable_recursive<wknd_self_t> |
|
957 > |
|
958 > |
|
959 , mpl::identity< specified_types > |
|
960 >::type recursive_enabled_types; |
|
961 |
|
962 public: // public typedefs |
|
963 |
|
964 typedef typename mpl::transform< |
|
965 recursive_enabled_types |
|
966 , unwrap_recursive<mpl::_1> |
|
967 >::type types; |
|
968 |
|
969 private: // internal typedefs |
|
970 |
|
971 typedef typename mpl::transform< |
|
972 recursive_enabled_types |
|
973 , mpl::protect< detail::make_reference_content<> > |
|
974 >::type internal_types; |
|
975 |
|
976 typedef typename mpl::front< |
|
977 internal_types |
|
978 >::type internal_T0; |
|
979 |
|
980 #else // defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) |
|
981 |
|
982 private: // helpers, for typedefs (below) |
|
983 |
|
984 typedef unwrapped_T0_ T0; |
|
985 |
|
986 #define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS(z,N,_) \ |
|
987 typedef typename mpl::eval_if< \ |
|
988 is_recursive_ \ |
|
989 , detail::variant::enable_recursive< \ |
|
990 BOOST_PP_CAT(T,N) \ |
|
991 , wknd_self_t \ |
|
992 > \ |
|
993 , mpl::identity< BOOST_PP_CAT(T,N) > \ |
|
994 >::type BOOST_PP_CAT(recursive_enabled_T,N); \ |
|
995 /**/ |
|
996 |
|
997 BOOST_PP_REPEAT( |
|
998 BOOST_VARIANT_LIMIT_TYPES |
|
999 , BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS |
|
1000 , _ |
|
1001 ) |
|
1002 |
|
1003 #undef BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS |
|
1004 |
|
1005 #define BOOST_VARIANT_AUX_UNWRAP_RECURSIVE_TYPEDEFS(z,N,_) \ |
|
1006 typedef typename unwrap_recursive< \ |
|
1007 BOOST_PP_CAT(recursive_enabled_T,N) \ |
|
1008 >::type BOOST_PP_CAT(public_T,N); \ |
|
1009 /**/ |
|
1010 |
|
1011 BOOST_PP_REPEAT( |
|
1012 BOOST_VARIANT_LIMIT_TYPES |
|
1013 , BOOST_VARIANT_AUX_UNWRAP_RECURSIVE_TYPEDEFS |
|
1014 , _ |
|
1015 ) |
|
1016 |
|
1017 #undef BOOST_VARIANT_AUX_UNWRAP_RECURSIVE_TYPEDEFS |
|
1018 |
|
1019 public: // public typedefs |
|
1020 |
|
1021 typedef typename detail::variant::make_variant_list< |
|
1022 BOOST_VARIANT_ENUM_PARAMS(public_T) |
|
1023 >::type types; |
|
1024 |
|
1025 private: // helpers, for internal typedefs (below) |
|
1026 |
|
1027 #define BOOST_VARIANT_AUX_MAKE_REFERENCE_CONTENT_TYPEDEFS(z,N,_) \ |
|
1028 typedef detail::make_reference_content< \ |
|
1029 BOOST_PP_CAT(recursive_enabled_T,N) \ |
|
1030 >::type BOOST_PP_CAT(internal_T,N); \ |
|
1031 /**/ |
|
1032 |
|
1033 BOOST_PP_REPEAT( |
|
1034 BOOST_VARIANT_LIMIT_TYPES |
|
1035 , BOOST_VARIANT_AUX_MAKE_REFERENCE_CONTENT_TYPEDEFS |
|
1036 , _ |
|
1037 ) |
|
1038 |
|
1039 #undef BOOST_VARIANT_AUX_MAKE_REFERENCE_CONTENT_TYPEDEFS |
|
1040 |
|
1041 private: // internal typedefs |
|
1042 |
|
1043 typedef typename detail::variant::make_variant_list< |
|
1044 BOOST_VARIANT_ENUM_PARAMS(internal_T) |
|
1045 >::type internal_types; |
|
1046 |
|
1047 private: // static precondition assertions |
|
1048 |
|
1049 // NOTE TO USER : |
|
1050 // variant< type-sequence > syntax is not supported on this compiler! |
|
1051 // |
|
1052 BOOST_MPL_ASSERT_NOT(( is_sequence_based_ )); |
|
1053 |
|
1054 #endif // BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT workaround |
|
1055 |
|
1056 private: // helpers, for representation (below) |
|
1057 |
|
1058 typedef typename detail::variant::find_fallback_type< |
|
1059 internal_types |
|
1060 >::type fallback_type_result_; |
|
1061 |
|
1062 typedef typename fallback_type_result_::first |
|
1063 fallback_type_index_; |
|
1064 typedef typename fallback_type_result_::second |
|
1065 fallback_type_; |
|
1066 |
|
1067 struct has_fallback_type_ |
|
1068 : mpl::not_< |
|
1069 is_same< fallback_type_, detail::variant::no_fallback_type > |
|
1070 > |
|
1071 { |
|
1072 }; |
|
1073 |
|
1074 typedef has_fallback_type_ |
|
1075 never_uses_backup_flag; |
|
1076 |
|
1077 typedef typename detail::variant::make_storage< |
|
1078 internal_types, never_uses_backup_flag |
|
1079 >::type storage_t; |
|
1080 |
|
1081 private: // helpers, for representation (below) |
|
1082 |
|
1083 // which_ on: |
|
1084 // * [0, size<internal_types>) indicates stack content |
|
1085 // * [-size<internal_types>, 0) indicates pointer to heap backup |
|
1086 // if which_ >= 0: |
|
1087 // * then which() -> which_ |
|
1088 // * else which() -> -(which_ + 1) |
|
1089 |
|
1090 #if !defined(BOOST_VARIANT_MINIMIZE_SIZE) |
|
1091 |
|
1092 typedef int which_t; |
|
1093 |
|
1094 #else // defined(BOOST_VARIANT_MINIMIZE_SIZE) |
|
1095 |
|
1096 // [if O1_size available, then attempt which_t size optimization...] |
|
1097 // [select signed char if fewer than SCHAR_MAX types, else signed int:] |
|
1098 typedef typename mpl::eval_if< |
|
1099 mpl::equal_to< mpl::O1_size<internal_types>, mpl::long_<-1> > |
|
1100 , mpl::identity< int > |
|
1101 , mpl::if_< |
|
1102 mpl::less< mpl::O1_size<internal_types>, mpl::int_<SCHAR_MAX> > |
|
1103 , signed char |
|
1104 , int |
|
1105 > |
|
1106 >::type which_t; |
|
1107 |
|
1108 #endif // BOOST_VARIANT_MINIMIZE_SIZE switch |
|
1109 |
|
1110 // representation -- private when possible |
|
1111 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
|
1112 private: |
|
1113 #else |
|
1114 public: |
|
1115 #endif |
|
1116 |
|
1117 which_t which_; |
|
1118 storage_t storage_; |
|
1119 |
|
1120 void indicate_which(int which) |
|
1121 { |
|
1122 which_ = static_cast<which_t>( which ); |
|
1123 } |
|
1124 |
|
1125 void indicate_backup_which(int which) |
|
1126 { |
|
1127 which_ = static_cast<which_t>( -(which + 1) ); |
|
1128 } |
|
1129 |
|
1130 private: // helpers, for queries (below) |
|
1131 |
|
1132 bool using_backup() const |
|
1133 { |
|
1134 return which_ < 0; |
|
1135 } |
|
1136 |
|
1137 public: // queries |
|
1138 |
|
1139 int which() const |
|
1140 { |
|
1141 // If using heap backup... |
|
1142 if (using_backup()) |
|
1143 // ...then return adjusted which_: |
|
1144 return -(which_ + 1); |
|
1145 |
|
1146 // Otherwise, return which_ directly: |
|
1147 return which_; |
|
1148 } |
|
1149 |
|
1150 private: // helpers, for structors (below) |
|
1151 |
|
1152 struct initializer |
|
1153 : BOOST_VARIANT_AUX_INITIALIZER_T( |
|
1154 recursive_enabled_types, recursive_enabled_T |
|
1155 ) |
|
1156 { |
|
1157 }; |
|
1158 |
|
1159 void destroy_content() |
|
1160 { |
|
1161 detail::variant::destroyer visitor; |
|
1162 this->internal_apply_visitor(visitor); |
|
1163 } |
|
1164 |
|
1165 public: // structors |
|
1166 |
|
1167 ~variant() |
|
1168 { |
|
1169 destroy_content(); |
|
1170 } |
|
1171 |
|
1172 variant() |
|
1173 { |
|
1174 // NOTE TO USER : |
|
1175 // Compile error from here indicates that the first bound |
|
1176 // type is not default-constructible, and so variant cannot |
|
1177 // support its own default-construction. |
|
1178 // |
|
1179 new( storage_.address() ) internal_T0(); |
|
1180 indicate_which(0); // zero is the index of the first bounded type |
|
1181 } |
|
1182 |
|
1183 private: // helpers, for structors, cont. (below) |
|
1184 |
|
1185 class convert_copy_into |
|
1186 : public static_visitor<int> |
|
1187 { |
|
1188 private: // representation |
|
1189 |
|
1190 void* storage_; |
|
1191 |
|
1192 public: // structors |
|
1193 |
|
1194 explicit convert_copy_into(void* storage) |
|
1195 : storage_(storage) |
|
1196 { |
|
1197 } |
|
1198 |
|
1199 public: // internal visitor interfaces (below) |
|
1200 |
|
1201 template <typename T> |
|
1202 int internal_visit(T& operand, int) const |
|
1203 { |
|
1204 // NOTE TO USER : |
|
1205 // Compile error here indicates one of the source variant's types |
|
1206 // cannot be unambiguously converted to the destination variant's |
|
1207 // types (or that no conversion exists). |
|
1208 // |
|
1209 return initializer::initialize(storage_, operand); |
|
1210 } |
|
1211 |
|
1212 # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) |
|
1213 template <typename T> |
|
1214 result_type internal_visit(const T& operand, int) const |
|
1215 { |
|
1216 return initializer::initialize(storage_, operand); |
|
1217 } |
|
1218 # endif |
|
1219 |
|
1220 template <typename T> |
|
1221 int internal_visit(boost::detail::reference_content<T>& operand, long) const |
|
1222 { |
|
1223 return internal_visit( operand.get(), 1L ); |
|
1224 } |
|
1225 |
|
1226 template <typename T> |
|
1227 int internal_visit(const boost::detail::reference_content<T>& operand, long) const |
|
1228 { |
|
1229 return internal_visit( operand.get(), 1L ); |
|
1230 } |
|
1231 |
|
1232 template <typename T> |
|
1233 int internal_visit(boost::detail::variant::backup_holder<T>& operand, long) const |
|
1234 { |
|
1235 return internal_visit( operand.get(), 1L ); |
|
1236 } |
|
1237 |
|
1238 template <typename T> |
|
1239 int internal_visit(const boost::detail::variant::backup_holder<T>& operand, long) const |
|
1240 { |
|
1241 return internal_visit( operand.get(), 1L ); |
|
1242 } |
|
1243 |
|
1244 template <typename T> |
|
1245 int internal_visit(boost::recursive_wrapper<T>& operand, long) const |
|
1246 { |
|
1247 return internal_visit( operand.get(), 1L ); |
|
1248 } |
|
1249 |
|
1250 template <typename T> |
|
1251 int internal_visit(const boost::recursive_wrapper<T>& operand, long) const |
|
1252 { |
|
1253 return internal_visit( operand.get(), 1L ); |
|
1254 } |
|
1255 |
|
1256 }; |
|
1257 |
|
1258 friend class convert_copy_into; |
|
1259 |
|
1260 private: // helpers, for structors, below |
|
1261 |
|
1262 template <typename T> |
|
1263 void convert_construct( |
|
1264 T& operand |
|
1265 , int |
|
1266 , mpl::false_ = mpl::false_() // is_foreign_variant |
|
1267 ) |
|
1268 { |
|
1269 // NOTE TO USER : |
|
1270 // Compile error here indicates that the given type is not |
|
1271 // unambiguously convertible to one of the variant's types |
|
1272 // (or that no conversion exists). |
|
1273 // |
|
1274 indicate_which( |
|
1275 initializer::initialize( |
|
1276 storage_.address() |
|
1277 , operand |
|
1278 ) |
|
1279 ); |
|
1280 } |
|
1281 |
|
1282 template <typename Variant> |
|
1283 void convert_construct( |
|
1284 Variant& operand |
|
1285 , long |
|
1286 , mpl::true_// is_foreign_variant |
|
1287 ) |
|
1288 { |
|
1289 convert_copy_into visitor(storage_.address()); |
|
1290 indicate_which( |
|
1291 operand.internal_apply_visitor(visitor) |
|
1292 ); |
|
1293 } |
|
1294 |
|
1295 template <typename Variant> |
|
1296 void convert_construct_variant(Variant& operand) |
|
1297 { |
|
1298 // [Determine if the given variant is itself a bounded type, or if its |
|
1299 // content needs to be converted (i.e., it is a 'foreign' variant):] |
|
1300 // |
|
1301 |
|
1302 typedef typename mpl::find_if< |
|
1303 types |
|
1304 , is_same< |
|
1305 add_const<mpl::_1> |
|
1306 , const Variant |
|
1307 > |
|
1308 >::type found_it; |
|
1309 |
|
1310 typedef typename mpl::end<types>::type not_found; |
|
1311 typedef typename is_same< |
|
1312 found_it, not_found |
|
1313 >::type is_foreign_variant; |
|
1314 |
|
1315 // Convert construct from operand: |
|
1316 convert_construct( |
|
1317 operand, 1L |
|
1318 , is_foreign_variant() |
|
1319 ); |
|
1320 } |
|
1321 |
|
1322 template <BOOST_VARIANT_ENUM_PARAMS(typename U)> |
|
1323 void convert_construct( |
|
1324 boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>& operand |
|
1325 , long |
|
1326 ) |
|
1327 { |
|
1328 convert_construct_variant(operand); |
|
1329 } |
|
1330 |
|
1331 template <BOOST_VARIANT_ENUM_PARAMS(typename U)> |
|
1332 void convert_construct( |
|
1333 const boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>& operand |
|
1334 , long |
|
1335 ) |
|
1336 { |
|
1337 convert_construct_variant(operand); |
|
1338 } |
|
1339 |
|
1340 public: // structors, cont. |
|
1341 |
|
1342 #if !defined(BOOST_VARIANT_AUX_BROKEN_CONSTRUCTOR_TEMPLATE_ORDERING) |
|
1343 |
|
1344 template <typename T> |
|
1345 variant(const T& operand) |
|
1346 { |
|
1347 convert_construct(operand, 1L); |
|
1348 } |
|
1349 |
|
1350 template <typename T> |
|
1351 variant(T& operand) |
|
1352 { |
|
1353 convert_construct(operand, 1L); |
|
1354 } |
|
1355 |
|
1356 #elif defined(BOOST_VARIANT_AUX_HAS_CONSTRUCTOR_TEMPLATE_ORDERING_SFINAE_WKND) |
|
1357 |
|
1358 // For compilers that cannot distinguish between T& and const T& in |
|
1359 // template constructors, but do fully support SFINAE, we can workaround: |
|
1360 |
|
1361 template <typename T> |
|
1362 variant(const T& operand) |
|
1363 { |
|
1364 convert_construct(operand, 1L); |
|
1365 } |
|
1366 |
|
1367 template <typename T> |
|
1368 variant( |
|
1369 T& operand |
|
1370 , typename enable_if< |
|
1371 mpl::not_< is_const<T> > |
|
1372 , void |
|
1373 >::type* = 0 |
|
1374 ) |
|
1375 { |
|
1376 convert_construct(operand, 1L); |
|
1377 } |
|
1378 |
|
1379 #else // !defined(BOOST_VARIANT_AUX_HAS_CONSTRUCTOR_TEMPLATE_ORDERING_SFINAE_WKND) |
|
1380 |
|
1381 // For compilers that cannot distinguish between T& and const T& in |
|
1382 // template constructors, and do NOT support SFINAE, we can't workaround: |
|
1383 |
|
1384 template <typename T> |
|
1385 variant(const T& operand) |
|
1386 { |
|
1387 convert_construct(operand, 1L); |
|
1388 } |
|
1389 |
|
1390 #endif // BOOST_VARIANT_AUX_BROKEN_CONSTRUCTOR_TEMPLATE_ORDERING workarounds |
|
1391 |
|
1392 public: // structors, cont. |
|
1393 |
|
1394 // [MSVC6 requires copy constructor appear after template constructors] |
|
1395 variant(const variant& operand) |
|
1396 { |
|
1397 // Copy the value of operand into *this... |
|
1398 detail::variant::copy_into visitor( storage_.address() ); |
|
1399 operand.internal_apply_visitor(visitor); |
|
1400 |
|
1401 // ...and activate the *this's primary storage on success: |
|
1402 indicate_which(operand.which()); |
|
1403 } |
|
1404 |
|
1405 private: // helpers, for modifiers (below) |
|
1406 |
|
1407 # if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
|
1408 template <typename Variant, typename RhsT> |
|
1409 friend class detail::variant::backup_assigner; |
|
1410 # endif |
|
1411 |
|
1412 // class assigner |
|
1413 // |
|
1414 // Internal visitor that "assigns" the visited value to the given variant |
|
1415 // by appropriate destruction and copy-construction. |
|
1416 // |
|
1417 |
|
1418 class assigner |
|
1419 : public static_visitor<> |
|
1420 { |
|
1421 private: // representation |
|
1422 |
|
1423 variant& lhs_; |
|
1424 int rhs_which_; |
|
1425 |
|
1426 public: // structors |
|
1427 |
|
1428 assigner(variant& lhs, int rhs_which) |
|
1429 : lhs_(lhs) |
|
1430 , rhs_which_(rhs_which) |
|
1431 { |
|
1432 } |
|
1433 |
|
1434 private: // helpers, for internal visitor interface (below) |
|
1435 |
|
1436 template <typename RhsT, typename B1, typename B2> |
|
1437 void assign_impl( |
|
1438 const RhsT& rhs_content |
|
1439 , mpl::true_// has_nothrow_copy |
|
1440 , B1// has_nothrow_move_constructor |
|
1441 , B2// has_fallback_type |
|
1442 ) |
|
1443 { |
|
1444 // Destroy lhs's content... |
|
1445 lhs_.destroy_content(); // nothrow |
|
1446 |
|
1447 // ...copy rhs content into lhs's storage... |
|
1448 new(lhs_.storage_.address()) |
|
1449 RhsT( rhs_content ); // nothrow |
|
1450 |
|
1451 // ...and indicate new content type: |
|
1452 lhs_.indicate_which(rhs_which_); // nothrow |
|
1453 } |
|
1454 |
|
1455 template <typename RhsT, typename B> |
|
1456 void assign_impl( |
|
1457 const RhsT& rhs_content |
|
1458 , mpl::false_// has_nothrow_copy |
|
1459 , mpl::true_// has_nothrow_move_constructor |
|
1460 , B// has_fallback_type |
|
1461 ) |
|
1462 { |
|
1463 // Attempt to make a temporary copy (so as to move it below)... |
|
1464 RhsT temp(rhs_content); |
|
1465 |
|
1466 // ...and upon success destroy lhs's content... |
|
1467 lhs_.destroy_content(); // nothrow |
|
1468 |
|
1469 // ...move the temporary copy into lhs's storage... |
|
1470 new(lhs_.storage_.address()) |
|
1471 RhsT( detail::variant::move(temp) ); // nothrow |
|
1472 |
|
1473 // ...and indicate new content type: |
|
1474 lhs_.indicate_which(rhs_which_); // nothrow |
|
1475 } |
|
1476 |
|
1477 template <typename RhsT> |
|
1478 void assign_impl( |
|
1479 const RhsT& rhs_content |
|
1480 , mpl::false_// has_nothrow_copy |
|
1481 , mpl::false_// has_nothrow_move_constructor |
|
1482 , mpl::true_// has_fallback_type |
|
1483 ) |
|
1484 { |
|
1485 // Destroy lhs's content... |
|
1486 lhs_.destroy_content(); // nothrow |
|
1487 |
|
1488 try |
|
1489 { |
|
1490 // ...and attempt to copy rhs's content into lhs's storage: |
|
1491 new(lhs_.storage_.address()) |
|
1492 RhsT( rhs_content ); |
|
1493 } |
|
1494 catch (...) |
|
1495 { |
|
1496 // In case of failure, default-construct fallback type in lhs's storage... |
|
1497 new (lhs_.storage_.address()) |
|
1498 fallback_type_; // nothrow |
|
1499 |
|
1500 // ...indicate construction of fallback type... |
|
1501 lhs_.indicate_which( |
|
1502 BOOST_MPL_AUX_VALUE_WKND(fallback_type_index_)::value |
|
1503 ); // nothrow |
|
1504 |
|
1505 // ...and rethrow: |
|
1506 throw; |
|
1507 } |
|
1508 |
|
1509 // In the event of success, indicate new content type: |
|
1510 lhs_.indicate_which(rhs_which_); // nothrow |
|
1511 } |
|
1512 |
|
1513 template <typename RhsT> |
|
1514 void assign_impl( |
|
1515 const RhsT& rhs_content |
|
1516 , mpl::false_// has_nothrow_copy |
|
1517 , mpl::false_// has_nothrow_move_constructor |
|
1518 , mpl::false_// has_fallback_type |
|
1519 ) |
|
1520 { |
|
1521 detail::variant::backup_assigner<wknd_self_t, RhsT> |
|
1522 visitor(lhs_, rhs_which_, rhs_content); |
|
1523 lhs_.internal_apply_visitor(visitor); |
|
1524 } |
|
1525 |
|
1526 public: // internal visitor interfaces |
|
1527 |
|
1528 template <typename RhsT> |
|
1529 BOOST_VARIANT_AUX_RETURN_VOID_TYPE |
|
1530 internal_visit(const RhsT& rhs_content, int) |
|
1531 { |
|
1532 typedef typename has_nothrow_copy<RhsT>::type |
|
1533 nothrow_copy; |
|
1534 typedef typename mpl::or_< // reduces compile-time |
|
1535 nothrow_copy |
|
1536 , detail::variant::has_nothrow_move_constructor<RhsT> |
|
1537 >::type nothrow_move_constructor; |
|
1538 |
|
1539 assign_impl( |
|
1540 rhs_content |
|
1541 , nothrow_copy() |
|
1542 , nothrow_move_constructor() |
|
1543 , has_fallback_type_() |
|
1544 ); |
|
1545 |
|
1546 BOOST_VARIANT_AUX_RETURN_VOID; |
|
1547 } |
|
1548 |
|
1549 }; |
|
1550 |
|
1551 friend class assigner; |
|
1552 |
|
1553 void variant_assign(const variant& rhs) |
|
1554 { |
|
1555 // If the contained types are EXACTLY the same... |
|
1556 if (which_ == rhs.which_) |
|
1557 { |
|
1558 // ...then assign rhs's storage to lhs's content: |
|
1559 detail::variant::assign_storage visitor(rhs.storage_.address()); |
|
1560 this->internal_apply_visitor(visitor); |
|
1561 } |
|
1562 else |
|
1563 { |
|
1564 // Otherwise, perform general (copy-based) variant assignment: |
|
1565 assigner visitor(*this, rhs.which()); |
|
1566 rhs.internal_apply_visitor(visitor); |
|
1567 } |
|
1568 } |
|
1569 |
|
1570 private: // helpers, for modifiers (below) |
|
1571 |
|
1572 template <typename T> |
|
1573 void assign(const T& rhs) |
|
1574 { |
|
1575 // If direct T-to-T assignment is not possible... |
|
1576 detail::variant::direct_assigner<const T> direct_assign(rhs); |
|
1577 if (this->apply_visitor(direct_assign) == false) |
|
1578 { |
|
1579 // ...then convert rhs to variant and assign: |
|
1580 // |
|
1581 // While potentially inefficient, the following construction of a |
|
1582 // variant allows T as any type convertible to one of the bounded |
|
1583 // types without excessive code redundancy. |
|
1584 // |
|
1585 variant temp(rhs); |
|
1586 variant_assign( detail::variant::move(temp) ); |
|
1587 } |
|
1588 } |
|
1589 |
|
1590 public: // modifiers |
|
1591 |
|
1592 template <typename T> |
|
1593 variant& operator=(const T& rhs) |
|
1594 { |
|
1595 assign(rhs); |
|
1596 return *this; |
|
1597 } |
|
1598 |
|
1599 // [MSVC6 requires copy assign appear after templated operator=] |
|
1600 variant& operator=(const variant& rhs) |
|
1601 { |
|
1602 variant_assign(rhs); |
|
1603 return *this; |
|
1604 } |
|
1605 |
|
1606 void swap(variant& rhs) |
|
1607 { |
|
1608 // If the contained types are the same... |
|
1609 if (which() == rhs.which()) |
|
1610 { |
|
1611 // ...then swap the values directly: |
|
1612 detail::variant::swap_with<variant> visitor(rhs); |
|
1613 this->apply_visitor(visitor); |
|
1614 } |
|
1615 else |
|
1616 { |
|
1617 // ...otherwise, perform general variant swap: |
|
1618 variant tmp( detail::variant::move(rhs) ); |
|
1619 rhs = detail::variant::move(*this); |
|
1620 *this = detail::variant::move(tmp); |
|
1621 } |
|
1622 } |
|
1623 |
|
1624 public: // queries |
|
1625 |
|
1626 // |
|
1627 // NOTE: member which() defined above. |
|
1628 // |
|
1629 |
|
1630 bool empty() const |
|
1631 { |
|
1632 return false; |
|
1633 } |
|
1634 |
|
1635 const std::type_info& type() const |
|
1636 { |
|
1637 detail::variant::reflect visitor; |
|
1638 return this->apply_visitor(visitor); |
|
1639 } |
|
1640 |
|
1641 public: // prevent comparison with foreign types |
|
1642 |
|
1643 #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) |
|
1644 |
|
1645 # define BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE \ |
|
1646 void |
|
1647 |
|
1648 #else // MSVC7 |
|
1649 |
|
1650 // |
|
1651 // MSVC7 gives error about return types for above being different than |
|
1652 // the true comparison operator overloads: |
|
1653 // |
|
1654 |
|
1655 # define BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE \ |
|
1656 bool |
|
1657 |
|
1658 #endif // MSVC7 workaround |
|
1659 |
|
1660 template <typename U> |
|
1661 BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE |
|
1662 operator==(const U&) const |
|
1663 { |
|
1664 BOOST_STATIC_ASSERT( false && sizeof(U) ); |
|
1665 } |
|
1666 |
|
1667 template <typename U> |
|
1668 BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE |
|
1669 operator<(const U&) const |
|
1670 { |
|
1671 BOOST_STATIC_ASSERT( false && sizeof(U) ); |
|
1672 } |
|
1673 |
|
1674 public: // comparison operators |
|
1675 |
|
1676 // [MSVC6 requires these operators appear after template operators] |
|
1677 |
|
1678 bool operator==(const variant& rhs) const |
|
1679 { |
|
1680 if (this->which() != rhs.which()) |
|
1681 return false; |
|
1682 |
|
1683 detail::variant::comparer< |
|
1684 variant, detail::variant::equal_comp |
|
1685 > visitor(*this); |
|
1686 return rhs.apply_visitor(visitor); |
|
1687 } |
|
1688 |
|
1689 bool operator<(const variant& rhs) const |
|
1690 { |
|
1691 // |
|
1692 // Dirk Schreib suggested this collating order. |
|
1693 // |
|
1694 |
|
1695 if (this->which() != rhs.which()) |
|
1696 return this->which() < rhs.which(); |
|
1697 |
|
1698 detail::variant::comparer< |
|
1699 variant, detail::variant::less_comp |
|
1700 > visitor(*this); |
|
1701 return rhs.apply_visitor(visitor); |
|
1702 } |
|
1703 |
|
1704 // helpers, for visitation support (below) -- private when possible |
|
1705 #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
|
1706 |
|
1707 template < BOOST_VARIANT_ENUM_PARAMS(typename U) > |
|
1708 friend class variant; |
|
1709 |
|
1710 private: |
|
1711 |
|
1712 #else// defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
|
1713 |
|
1714 public: |
|
1715 |
|
1716 #endif// !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) |
|
1717 |
|
1718 template <typename Visitor, typename VoidPtrCV> |
|
1719 static |
|
1720 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( |
|
1721 typename Visitor::result_type |
|
1722 ) |
|
1723 internal_apply_visitor_impl( |
|
1724 int internal_which |
|
1725 , int logical_which |
|
1726 , Visitor& visitor |
|
1727 , VoidPtrCV storage |
|
1728 ) |
|
1729 { |
|
1730 typedef mpl::int_<0> first_which; |
|
1731 typedef typename mpl::begin<internal_types>::type first_it; |
|
1732 typedef typename mpl::end<internal_types>::type last_it; |
|
1733 |
|
1734 typedef detail::variant::visitation_impl_step< |
|
1735 first_it, last_it |
|
1736 > first_step; |
|
1737 |
|
1738 return detail::variant::visitation_impl( |
|
1739 internal_which, logical_which |
|
1740 , visitor, storage, mpl::false_() |
|
1741 , never_uses_backup_flag() |
|
1742 , static_cast<first_which*>(0), static_cast<first_step*>(0) |
|
1743 ); |
|
1744 } |
|
1745 |
|
1746 template <typename Visitor> |
|
1747 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( |
|
1748 typename Visitor::result_type |
|
1749 ) |
|
1750 internal_apply_visitor(Visitor& visitor) |
|
1751 { |
|
1752 return internal_apply_visitor_impl( |
|
1753 which_, which(), visitor, storage_.address() |
|
1754 ); |
|
1755 } |
|
1756 |
|
1757 template <typename Visitor> |
|
1758 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( |
|
1759 typename Visitor::result_type |
|
1760 ) |
|
1761 internal_apply_visitor(Visitor& visitor) const |
|
1762 { |
|
1763 return internal_apply_visitor_impl( |
|
1764 which_, which(), visitor, storage_.address() |
|
1765 ); |
|
1766 } |
|
1767 |
|
1768 public: // visitation support |
|
1769 |
|
1770 template <typename Visitor> |
|
1771 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( |
|
1772 typename Visitor::result_type |
|
1773 ) |
|
1774 apply_visitor(Visitor& visitor) |
|
1775 { |
|
1776 detail::variant::invoke_visitor<Visitor> invoker(visitor); |
|
1777 return this->internal_apply_visitor(invoker); |
|
1778 } |
|
1779 |
|
1780 template <typename Visitor> |
|
1781 BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( |
|
1782 typename Visitor::result_type |
|
1783 ) |
|
1784 apply_visitor(Visitor& visitor) const |
|
1785 { |
|
1786 detail::variant::invoke_visitor<Visitor> invoker(visitor); |
|
1787 return this->internal_apply_visitor(invoker); |
|
1788 } |
|
1789 |
|
1790 }; // class variant |
|
1791 |
|
1792 /////////////////////////////////////////////////////////////////////////////// |
|
1793 // metafunction make_variant_over |
|
1794 // |
|
1795 // See docs and boost/variant/variant_fwd.hpp for more information. |
|
1796 // |
|
1797 template <typename Types> |
|
1798 struct make_variant_over |
|
1799 { |
|
1800 private: // precondition assertions |
|
1801 |
|
1802 #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) |
|
1803 BOOST_STATIC_ASSERT(( ::boost::mpl::is_sequence<Types>::value )); |
|
1804 #endif |
|
1805 |
|
1806 public: // metafunction result |
|
1807 |
|
1808 typedef variant< |
|
1809 detail::variant::over_sequence< Types > |
|
1810 > type; |
|
1811 |
|
1812 }; |
|
1813 |
|
1814 /////////////////////////////////////////////////////////////////////////////// |
|
1815 // function template swap |
|
1816 // |
|
1817 // Swaps two variants of the same type (i.e., identical specification). |
|
1818 // |
|
1819 template < BOOST_VARIANT_ENUM_PARAMS(typename T) > |
|
1820 inline void swap( |
|
1821 variant< BOOST_VARIANT_ENUM_PARAMS(T) >& lhs |
|
1822 , variant< BOOST_VARIANT_ENUM_PARAMS(T) >& rhs |
|
1823 ) |
|
1824 { |
|
1825 lhs.swap(rhs); |
|
1826 } |
|
1827 |
|
1828 } // namespace boost |
|
1829 |
|
1830 // implementation additions |
|
1831 #include "boost/variant/detail/variant_io.hpp" |
|
1832 |
|
1833 #endif // BOOST_VARIANT_VARIANT_HPP |
|