1//-----------------------------------------------------------------------------
2// boost variant/variant.hpp header file
3// See http://www.boost.org for updates, documentation, and revision history.
4//-----------------------------------------------------------------------------
5//
6// Copyright (c) 2002-2003 Eric Friedman, Itay Maman
7// Copyright (c) 2012-2024 Antony Polukhin
8//
9// Distributed under the Boost Software License, Version 1.0. (See
10// accompanying file LICENSE_1_0.txt or copy at
11// http://www.boost.org/LICENSE_1_0.txt)
12
13// Thanks to Adam Romanek for providing patches for exception-disabled env.
14
15#ifndef BOOST_VARIANT_VARIANT_HPP
16#define BOOST_VARIANT_VARIANT_HPP
17
18#include <cstddef> // for std::size_t
19#include <new> // for placement new
20
21#include <boost/type_index.hpp>
22
23#include <boost/variant/detail/config.hpp>
24#include <boost/mpl/aux_/value_wknd.hpp>
25
26#include <boost/variant/variant_fwd.hpp>
27#include <boost/variant/detail/backup_holder.hpp>
28#include <boost/variant/detail/enable_recursive_fwd.hpp>
29#include <boost/variant/detail/forced_return.hpp>
30#include <boost/variant/detail/initializer.hpp>
31#include <boost/variant/detail/make_variant_list.hpp>
32#include <boost/variant/detail/over_sequence.hpp>
33#include <boost/variant/detail/visitation_impl.hpp>
34#include <boost/variant/detail/hash_variant.hpp>
35#include <boost/variant/detail/std_hash.hpp>
36
37#include <boost/variant/detail/move.hpp>
38
39#include <boost/detail/reference_content.hpp>
40#include <boost/blank.hpp>
41#include <boost/integer/common_factor_ct.hpp>
42#include <boost/static_assert.hpp>
43#include <boost/type_traits/aligned_storage.hpp>
44#include <boost/type_traits/alignment_of.hpp>
45#include <boost/type_traits/add_const.hpp>
46#include <boost/type_traits/has_nothrow_constructor.hpp>
47#include <boost/type_traits/has_nothrow_copy.hpp>
48#include <boost/type_traits/is_nothrow_move_assignable.hpp>
49#include <boost/type_traits/is_nothrow_move_constructible.hpp>
50#include <boost/type_traits/is_const.hpp>
51#include <boost/type_traits/is_same.hpp>
52#include <boost/type_traits/is_rvalue_reference.hpp>
53#include <boost/type_traits/is_constructible.hpp>
54#include <boost/type_traits/add_lvalue_reference.hpp>
55#include <boost/type_traits/declval.hpp>
56#include <boost/core/no_exceptions_support.hpp>
57#include <boost/core/enable_if.hpp>
58#include <boost/variant/recursive_wrapper_fwd.hpp>
59#include <boost/variant/static_visitor.hpp>
60
61#include <boost/mpl/assert.hpp>
62#include <boost/mpl/begin_end.hpp>
63#include <boost/mpl/bool.hpp>
64#include <boost/mpl/deref.hpp>
65#include <boost/mpl/empty.hpp>
66#include <boost/mpl/eval_if.hpp>
67#include <boost/mpl/find_if.hpp>
68#include <boost/mpl/fold.hpp>
69#include <boost/mpl/front.hpp>
70#include <boost/mpl/identity.hpp>
71#include <boost/mpl/if.hpp>
72#include <boost/mpl/insert_range.hpp>
73#include <boost/mpl/int.hpp>
74#include <boost/mpl/is_sequence.hpp>
75#include <boost/mpl/iterator_range.hpp>
76#include <boost/mpl/iter_fold_if.hpp>
77#include <boost/mpl/list.hpp>
78#include <boost/mpl/logical.hpp>
79#include <boost/mpl/max_element.hpp>
80#include <boost/mpl/next.hpp>
81#include <boost/mpl/not.hpp>
82#include <boost/mpl/pair.hpp>
83#include <boost/mpl/protect.hpp>
84#include <boost/mpl/push_front.hpp>
85#include <boost/mpl/same_as.hpp>
86#include <boost/mpl/size_t.hpp>
87#include <boost/mpl/sizeof.hpp>
88#include <boost/mpl/transform.hpp>
89
90///////////////////////////////////////////////////////////////////////////////
91// Implementation Macros:
92//
93// BOOST_VARIANT_VISITATION_UNROLLING_LIMIT
94// Defined in boost/variant/detail/visitation_impl.hpp.
95//
96// BOOST_VARIANT_MINIMIZE_SIZE
97// When #defined, implementation employs all known means to minimize the
98// size of variant obje cts. However, often unsuccessful due to alignment
99// issues, and potentially harmful to runtime speed, so not enabled by
100// default. (TODO: Investigate further.)
101
102#if defined(BOOST_VARIANT_MINIMIZE_SIZE)
103# include <climits> // for SCHAR_MAX
104# include <boost/mpl/eval_if.hpp>
105# include <boost/mpl/equal_to.hpp>
106# include <boost/mpl/identity.hpp>
107# include <boost/mpl/int.hpp>
108# include <boost/mpl/if.hpp>
109# include <boost/mpl/less.hpp>
110# include <boost/mpl/long.hpp>
111# include <boost/mpl/O1_size.hpp>
112#endif
113
114
115namespace boost {
116
117namespace detail { namespace variant {
118
119///////////////////////////////////////////////////////////////////////////////
120// (detail) metafunction max_value
121//
122// Finds the maximum value of the unary metafunction F over Sequence.
123//
124template <typename Sequence, typename F>
125struct max_value
126{
127private: // helpers, for metafunction result (below)
128
129 typedef typename mpl::transform1<Sequence, F>::type transformed_;
130 typedef typename mpl::max_element<transformed_
131
132 >::type max_it;
133
134public: // metafunction result
135
136 typedef typename mpl::deref<max_it>::type
137 type;
138
139};
140
141struct add_alignment
142{
143 template <typename State, typename Item>
144 struct apply
145 : mpl::size_t<
146 ::boost::integer::static_lcm<
147 BOOST_MPL_AUX_VALUE_WKND(State)::value
148 , ::boost::alignment_of<Item>::value
149 >::value
150 >
151 {};
152};
153
154///////////////////////////////////////////////////////////////////////////////
155// (detail) metafunction find_fallback_type
156//
157// Provides a fallback (i.e., nothrow default-constructible) type from the
158// specified sequence, or no_fallback_type if not found.
159//
160// This implementation is designed to prefer boost::blank over other potential
161// fallback types, regardless of its position in the specified sequence.
162//
163
164class no_fallback_type;
165
166struct find_fallback_type_pred
167{
168 template <typename Iterator>
169 struct apply
170 {
171 private:
172 typedef typename mpl::deref<Iterator>::type t_;
173
174 public:
175 typedef mpl::not_< has_nothrow_constructor<t_> > type;
176 };
177};
178
179template <typename Types>
180struct find_fallback_type
181{
182private: // helpers, for metafunction result (below)
183
184 typedef typename mpl::end<Types>::type end_it;
185
186 // [Find the first suitable fallback type...]
187
188 typedef typename mpl::iter_fold_if<
189 Types
190 , mpl::int_<0>, mpl::protect< mpl::next<> >
191 , mpl::protect< find_fallback_type_pred >
192 >::type first_result_;
193
194 typedef typename first_result_::first first_result_index;
195 typedef typename first_result_::second first_result_it;
196
197 // [...now search the rest of the sequence for boost::blank...]
198
199 typedef typename mpl::iter_fold_if<
200 mpl::iterator_range< first_result_it,end_it >
201 , first_result_index, mpl::protect< mpl::next<> >
202 , mpl::protect< mpl::not_same_as<boost::blank> >
203 >::type second_result_;
204
205 typedef typename second_result_::second second_result_it;
206
207public: // metafunction result
208
209 // [...and return the results of the search:]
210 typedef typename mpl::eval_if<
211 is_same< second_result_it,end_it >
212 , mpl::if_<
213 is_same< first_result_it,end_it >
214 , mpl::pair< no_fallback_type,no_fallback_type >
215 , first_result_
216 >
217 , mpl::identity< second_result_ >
218 >::type type;
219
220};
221
222///////////////////////////////////////////////////////////////////////////////
223// (detail) metafunction is_variant_move_noexcept_constructible
224//
225// Returns true_type if all the types are nothrow move constructible.
226//
227template <class Types>
228struct is_variant_move_noexcept_constructible {
229 typedef typename boost::mpl::find_if<
230 Types, mpl::not_<boost::is_nothrow_move_constructible<boost::mpl::_1> >
231 >::type iterator_t;
232
233 typedef typename boost::mpl::end<Types>::type end_t;
234 typedef typename boost::is_same<
235 iterator_t, end_t
236 >::type type;
237};
238
239///////////////////////////////////////////////////////////////////////////////
240// (detail) metafunction is_variant_move_noexcept_assignable
241//
242// Returns true_type if all the types are nothrow move constructible.
243//
244template <class Types>
245struct is_variant_move_noexcept_assignable {
246 typedef typename boost::mpl::find_if<
247 Types, mpl::not_<boost::is_nothrow_move_assignable<boost::mpl::_1> >
248 >::type iterator_t;
249
250 typedef typename boost::mpl::end<Types>::type end_t;
251 typedef typename boost::is_same<
252 iterator_t, end_t
253 >::type type;
254};
255
256///////////////////////////////////////////////////////////////////////////////
257// (detail) metafunction is_variant_constructible_from
258//
259// Derives from true_type if at least one variant's type is constructible from T.
260//
261template <class T1, class T2>
262struct is_constructible_ext:
263 boost::mpl::or_<
264 boost::is_constructible<
265 T1,
266 T2
267 >,
268 boost::is_constructible<
269 T1,
270 typename boost::add_lvalue_reference<T2>::type
271 >
272 >
273{};
274
275template <class T, class Types>
276struct is_variant_constructible_from:
277 boost::mpl::not_< boost::is_same<
278 typename boost::mpl::find_if<
279 Types,
280 is_constructible_ext<boost::mpl::_1, T>
281 >::type,
282 typename boost::mpl::end<Types>::type
283 > >
284{};
285
286template <BOOST_VARIANT_ENUM_PARAMS(typename T), class Types>
287struct is_variant_constructible_from< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Types >:
288 boost::is_same<
289 typename boost::mpl::find_if<
290 typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::recursive_enabled_types,
291 mpl::not_< is_variant_constructible_from< boost::mpl::_1, Types> >
292 >::type,
293 typename boost::mpl::end< typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::recursive_enabled_types >::type
294 >
295{};
296
297template <BOOST_VARIANT_ENUM_PARAMS(typename T), class Types>
298struct is_variant_constructible_from< const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& , Types >:
299 is_variant_constructible_from<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Types >
300{};
301
302template <BOOST_VARIANT_ENUM_PARAMS(typename T), class Types>
303struct is_variant_constructible_from< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& , Types >:
304 is_variant_constructible_from<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Types >
305{};
306
307template <BOOST_VARIANT_ENUM_PARAMS(typename T), class Types>
308struct is_variant_constructible_from< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>&& , Types >:
309 is_variant_constructible_from<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Types >
310{};
311
312template <BOOST_VARIANT_ENUM_PARAMS(typename T), class Types>
313struct is_variant_constructible_from< boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const && , Types >:
314 is_variant_constructible_from<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Types >
315{};
316
317
318///////////////////////////////////////////////////////////////////////////////
319// (detail) metafunction make_storage
320//
321// Provides an aligned storage type capable of holding any of the types
322// specified in the given type-sequence.
323//
324
325template <typename Types, typename NeverUsesBackupFlag>
326struct make_storage
327{
328private: // helpers, for metafunction result (below)
329
330 typedef typename mpl::eval_if<
331 NeverUsesBackupFlag
332 , mpl::identity< Types >
333 , mpl::push_front<
334 Types, backup_holder<void*>
335 >
336 >::type types;
337
338 typedef typename max_value<
339 types, mpl::sizeof_<mpl::_1>
340 >::type max_size;
341
342#if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x0551))
343
344 typedef typename mpl::fold<
345 types
346 , mpl::size_t<1>
347 , add_alignment
348 >::type max_alignment;
349
350#else // borland
351
352 // temporary workaround -- use maximal alignment
353 typedef mpl::size_t< -1 > max_alignment;
354
355#endif // borland workaround
356
357public: // metafunction result
358
359 typedef ::boost::aligned_storage<
360 BOOST_MPL_AUX_VALUE_WKND(max_size)::value
361 , BOOST_MPL_AUX_VALUE_WKND(max_alignment)::value
362 > type;
363};
364
365///////////////////////////////////////////////////////////////////////////////
366// (detail) class destroyer
367//
368// Internal visitor that destroys the value it visits.
369//
370struct destroyer
371 : public static_visitor<>
372{
373public: // visitor interfaces
374
375 template <typename T>
376 void internal_visit(T& operand, int) const BOOST_NOEXCEPT
377 {
378 operand.~T(); // must be noexcept
379
380#if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x0551)) || \
381 BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
382 (void)operand; // suppresses warnings
383#endif
384 }
385
386};
387
388///////////////////////////////////////////////////////////////////////////////
389// (detail) class template known_get
390//
391// Visitor that returns a reference to content of the specified type.
392//
393// Precondition: visited variant MUST contain logical content of type T.
394//
395template <typename T>
396class known_get
397 : public static_visitor<T&>
398{
399
400public: // visitor interface
401
402 T& operator()(T& operand) const BOOST_NOEXCEPT
403 {
404 return operand;
405 }
406
407 template <typename U>
408 T& operator()(U&) const
409 {
410 // logical error to be here: see precondition above
411 return ::boost::detail::variant::forced_return< T& >();
412 }
413};
414
415///////////////////////////////////////////////////////////////////////////////
416// (detail) class copy_into
417//
418// Internal visitor that copies the value it visits into the given buffer.
419//
420class copy_into
421 : public static_visitor<>
422{
423private: // representation
424
425 void* storage_;
426
427public: // structors
428
429 explicit copy_into(void* storage) BOOST_NOEXCEPT
430 : storage_(storage)
431 {
432 }
433
434public: // internal visitor interface
435
436 template <typename T>
437 void internal_visit(boost::detail::variant::backup_holder<T>& operand, long) const
438 {
439 new(storage_) T( operand.get() );
440 }
441
442 template <typename T>
443 void internal_visit(const boost::detail::variant::backup_holder<T>& operand, long) const
444 {
445 new(storage_) T( operand.get() );
446 }
447
448 template <typename T>
449 void internal_visit(const T& operand, int) const
450 {
451 new(storage_) T(operand);
452 }
453
454};
455
456///////////////////////////////////////////////////////////////////////////////
457// (detail) class move_into
458//
459// Internal visitor that moves the value it visits into the given buffer.
460//
461class move_into
462 : public static_visitor<>
463{
464private: // representation
465
466 void* storage_;
467
468public: // structors
469
470 explicit move_into(void* storage) BOOST_NOEXCEPT
471 : storage_(storage)
472 {
473 }
474
475public: // internal visitor interface
476
477 template <typename T>
478 void internal_visit(boost::detail::variant::backup_holder<T>& operand, long) const
479 {
480 new(storage_) T( ::boost::detail::variant::move(operand.get()) );
481 }
482
483 template <typename T>
484 void internal_visit(T& operand, int) const BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T(boost::declval<T>())))
485 {
486 new(storage_) T(::boost::detail::variant::move(operand));
487 }
488};
489
490///////////////////////////////////////////////////////////////////////////////
491// (detail) class assign_storage
492//
493// Internal visitor that assigns the given storage (which must be a
494// constructed value of the same type) to the value it visits.
495//
496struct assign_storage
497 : public static_visitor<>
498{
499private: // representation
500
501 const void* rhs_storage_;
502
503public: // structors
504
505 explicit assign_storage(const void* rhs_storage) BOOST_NOEXCEPT
506 : rhs_storage_(rhs_storage)
507 {
508 }
509
510public: // internal visitor interfaces
511
512 template <typename T>
513 void internal_visit(backup_holder<T>& lhs_content, long) const
514 {
515 lhs_content.get()
516 = static_cast< const backup_holder<T>* >(rhs_storage_)->get();
517 }
518
519 template <typename T>
520 void internal_visit(const backup_holder<T>& lhs_content, long) const
521 {
522 lhs_content.get()
523 = static_cast< const backup_holder<T>* >(rhs_storage_)->get();
524 }
525
526 template <typename T>
527 void internal_visit(T& lhs_content, int) const
528 {
529 // NOTE TO USER :
530 // Compile error here indicates one of variant's bounded types does
531 // not meet the requirements of the Assignable concept. Thus,
532 // variant is not Assignable.
533 //
534 // Hint: Are any of the bounded types const-qualified or references?
535 //
536 lhs_content = *static_cast< const T* >(rhs_storage_);
537 }
538
539};
540
541///////////////////////////////////////////////////////////////////////////////
542// (detail) class move_storage
543//
544// Internal visitor that moves the given storage (which must be a
545// constructed value of the same type) to the value it visits.
546//
547struct move_storage
548 : public static_visitor<>
549{
550private: // representation
551
552 void* rhs_storage_;
553
554public: // structors
555
556 explicit move_storage(void* rhs_storage) BOOST_NOEXCEPT
557 : rhs_storage_(rhs_storage)
558 {
559 }
560
561public: // internal visitor interfaces
562
563 template <typename T>
564 void internal_visit(backup_holder<T>& lhs_content, long) const
565 {
566 lhs_content.get()
567 = ::boost::detail::variant::move(static_cast<backup_holder<T>* >(rhs_storage_)->get());
568 }
569
570 template <typename T>
571 void internal_visit(const backup_holder<T>& lhs_content, long) const
572 {
573 lhs_content.get()
574 = ::boost::detail::variant::move(static_cast<backup_holder<T>* >(rhs_storage_)->get());
575 }
576
577 template <typename T>
578 void internal_visit(T& lhs_content, int) const
579 {
580 // NOTE TO USER :
581 // Compile error here indicates one of variant's bounded types does
582 // not meet the requirements of the Assignable concept. Thus,
583 // variant is not Assignable.
584 //
585 // Hint: Are any of the bounded types const-qualified or references?
586 //
587 lhs_content = ::boost::detail::variant::move(*static_cast<T* >(rhs_storage_));
588 }
589
590};
591
592///////////////////////////////////////////////////////////////////////////////
593// (detail) class direct_assigner
594//
595// Generic static visitor that: if and only if the visited value is of the
596// specified type, assigns the given value to the visited value and returns
597// true; else returns false.
598//
599template <typename T>
600class direct_assigner
601 : public static_visitor<bool>
602{
603private: // representation
604
605 const T& rhs_;
606
607public: // structors
608
609 explicit direct_assigner(const T& rhs) BOOST_NOEXCEPT
610 : rhs_(rhs)
611 {
612 }
613
614public: // visitor interface
615
616 bool operator()(T& lhs)
617 {
618 lhs = rhs_;
619 return true;
620 }
621
622 template <typename U>
623 bool operator()(U&) BOOST_NOEXCEPT
624 {
625 return false;
626 }
627
628#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
629private:
630 // silence MSVC warning C4512: assignment operator could not be generated
631 direct_assigner& operator= (direct_assigner const&);
632#endif
633};
634
635///////////////////////////////////////////////////////////////////////////////
636// (detail) class direct_mover
637//
638// Generic static visitor that: if and only if the visited value is of the
639// specified type, move assigns the given value to the visited value and returns
640// true; else returns false.
641//
642template <typename T>
643class direct_mover
644 : public static_visitor<bool>
645{
646private: // representation
647
648 T& rhs_;
649
650public: // structors
651
652 explicit direct_mover(T& rhs) BOOST_NOEXCEPT
653 : rhs_(rhs)
654 {
655 }
656
657public: // visitor interface
658
659 bool operator()(T& lhs)
660 {
661 lhs = ::boost::detail::variant::move(rhs_);
662 return true;
663 }
664
665 template <typename U>
666 bool operator()(U&) BOOST_NOEXCEPT
667 {
668 return false;
669 }
670
671#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
672private:
673 // silence MSVC warning C4512: assignment operator could not be generated
674 direct_mover& operator= (direct_mover const&);
675#endif
676};
677
678
679///////////////////////////////////////////////////////////////////////////////
680// (detail) class backup_assigner
681//
682// Internal visitor that "assigns" the given value to the visited value,
683// using backup to recover if the destroy-copy sequence fails.
684//
685// NOTE: This needs to be a friend of variant, as it needs access to
686// indicate_which, indicate_backup_which, etc.
687//
688template <typename Variant>
689class backup_assigner
690 : public static_visitor<>
691{
692private: // representation
693
694 Variant& lhs_;
695 int rhs_which_;
696 const void* rhs_content_;
697 void (*copy_rhs_content_)(void*, const void*);
698
699public: // structors
700
701 template<class RhsT>
702 backup_assigner(Variant& lhs, int rhs_which, const RhsT& rhs_content)
703 : lhs_(lhs)
704 , rhs_which_(rhs_which)
705 , rhs_content_(&rhs_content)
706 , copy_rhs_content_(&construct_impl<RhsT>)
707 {
708 }
709
710private: // helpers, for visitor interface (below)
711
712 template<class RhsT>
713 static void construct_impl(void* addr, const void* obj)
714 {
715 new(addr) RhsT(*static_cast<const RhsT*>(obj));
716 }
717
718 template <typename LhsT>
719 void backup_assign_impl(
720 backup_holder<LhsT>& lhs_content
721 , mpl::false_ // is_nothrow_move_constructible
722 , long
723 )
724 {
725 // Move lhs content to backup...
726 backup_holder<LhsT> backup_lhs_content(0);
727 backup_lhs_content.swap(lhs_content); // nothrow
728
729 // ...destroy lhs content...
730 lhs_content.~backup_holder<LhsT>(); // nothrow
731
732 BOOST_TRY
733 {
734 // ...and attempt to copy rhs content into lhs storage:
735 copy_rhs_content_(lhs_.storage_.address(), rhs_content_);
736 }
737 BOOST_CATCH (...)
738 {
739 // In case of failure, copy backup pointer to lhs storage...
740 new(lhs_.storage_.address())
741 backup_holder<LhsT>( 0 ); // nothrow
742
743 static_cast<backup_holder<LhsT>* >(lhs_.storage_.address())
744 ->swap(backup_lhs_content); // nothrow
745
746 // ...and rethrow:
747 BOOST_RETHROW;
748 }
749 BOOST_CATCH_END
750
751 // In case of success, indicate new content type:
752 lhs_.indicate_which(rhs_which_); // nothrow
753 }
754
755 template <typename LhsT>
756 void backup_assign_impl(
757 LhsT& lhs_content
758 , mpl::true_ // is_nothrow_move_constructible
759 , int
760 )
761 {
762 // Move lhs content to backup...
763 LhsT backup_lhs_content(
764 ::boost::detail::variant::move(lhs_content)
765 ); // nothrow
766
767 // ...destroy lhs content...
768 lhs_content.~LhsT(); // nothrow
769
770 BOOST_TRY
771 {
772 // ...and attempt to copy rhs content into lhs storage:
773 copy_rhs_content_(lhs_.storage_.address(), rhs_content_);
774 }
775 BOOST_CATCH (...)
776 {
777 // In case of failure, restore backup content to lhs storage...
778 new(lhs_.storage_.address())
779 LhsT(
780 ::boost::detail::variant::move(backup_lhs_content)
781 ); // nothrow
782
783 // ...and rethrow:
784 BOOST_RETHROW;
785 }
786 BOOST_CATCH_END
787
788 // In case of success, indicate new content type:
789 lhs_.indicate_which(rhs_which_); // nothrow
790 }
791
792 template <typename LhsT>
793 void backup_assign_impl(
794 LhsT& lhs_content
795 , mpl::false_ // is_nothrow_move_constructible
796 , int
797 )
798 {
799 // Backup lhs content...
800 LhsT* backup_lhs_ptr = new LhsT(lhs_content);
801
802 // ...destroy lhs content...
803 lhs_content.~LhsT(); // nothrow
804
805 BOOST_TRY
806 {
807 // ...and attempt to copy rhs content into lhs storage:
808 copy_rhs_content_(lhs_.storage_.address(), rhs_content_);
809 }
810 BOOST_CATCH (...)
811 {
812 // In case of failure, copy backup pointer to lhs storage...
813 new(lhs_.storage_.address())
814 backup_holder<LhsT>( backup_lhs_ptr ); // nothrow
815
816 // ...indicate now using backup...
817 lhs_.indicate_backup_which( lhs_.which() ); // nothrow
818
819 // ...and rethrow:
820 BOOST_RETHROW;
821 }
822 BOOST_CATCH_END
823
824 // In case of success, indicate new content type...
825 lhs_.indicate_which(rhs_which_); // nothrow
826
827 // ...and delete backup:
828 delete backup_lhs_ptr; // nothrow
829 }
830
831public: // visitor interface
832
833 template <typename LhsT>
834 void internal_visit(LhsT& lhs_content, int)
835 {
836 typedef typename is_nothrow_move_constructible<LhsT>::type
837 nothrow_move;
838
839 backup_assign_impl( lhs_content, nothrow_move(), 1L);
840 }
841
842#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
843private:
844 // silence MSVC warning C4512: assignment operator could not be generated
845 backup_assigner& operator= (backup_assigner const&);
846#endif
847};
848
849///////////////////////////////////////////////////////////////////////////////
850// (detail) class swap_with
851//
852// Visitor that swaps visited value with content of given variant.
853//
854// Precondition: Given variant MUST have same logical type as visited value.
855//
856template <typename Variant>
857struct swap_with
858 : public static_visitor<>
859{
860private: // representation
861
862 Variant& toswap_;
863
864public: // structors
865
866 explicit swap_with(Variant& toswap) BOOST_NOEXCEPT
867 : toswap_(toswap)
868 {
869 }
870
871public: // internal visitor interfaces
872
873 template <typename T>
874 void operator()(T& operand) const
875 {
876 // Since the precondition ensures types are same, get T...
877 known_get<T> getter;
878 T& other = toswap_.apply_visitor(getter);
879
880 // ...and swap:
881 ::boost::detail::variant::move_swap( operand, other );
882 }
883
884private:
885 swap_with& operator=(const swap_with&);
886
887};
888
889///////////////////////////////////////////////////////////////////////////////
890// (detail) class reflect
891//
892// Generic static visitor that performs a typeid on the value it visits.
893//
894
895class reflect
896 : public static_visitor<const boost::typeindex::type_info&>
897{
898public: // visitor interfaces
899
900 template <typename T>
901 const boost::typeindex::type_info& operator()(const T&) const BOOST_NOEXCEPT
902 {
903 return boost::typeindex::type_id<T>().type_info();
904 }
905
906};
907
908///////////////////////////////////////////////////////////////////////////////
909// (detail) class comparer
910//
911// Generic static visitor that compares the content of the given lhs variant
912// with the visited rhs content using Comp.
913//
914// Precondition: lhs.which() == rhs.which()
915//
916template <typename Variant, typename Comp>
917class comparer
918 : public static_visitor<bool>
919{
920private: // representation
921
922 const Variant& lhs_;
923
924public: // structors
925
926 explicit comparer(const Variant& lhs) BOOST_NOEXCEPT
927 : lhs_(lhs)
928 {
929 }
930
931public: // visitor interfaces
932
933 template <typename T>
934 bool operator()(T& rhs_content) const
935 {
936 // Since the precondition ensures lhs and rhs types are same, get T...
937 known_get<T> getter;
938 const T& lhs_content = lhs_.apply_visitor(getter);
939
940 // ...and compare lhs and rhs contents:
941 return Comp()(lhs_content, rhs_content);
942 }
943
944private:
945 comparer& operator=(const comparer&);
946
947};
948
949///////////////////////////////////////////////////////////////////////////////
950// (detail) class equal_comp
951//
952// Generic function object compares lhs with rhs using operator==.
953//
954struct equal_comp
955{
956 template <typename T>
957 bool operator()(const T& lhs, const T& rhs) const
958 {
959 return lhs == rhs;
960 }
961};
962
963///////////////////////////////////////////////////////////////////////////////
964// (detail) class less_comp
965//
966// Generic function object compares lhs with rhs using operator<.
967//
968struct less_comp
969{
970 template <typename T>
971 bool operator()(const T& lhs, const T& rhs) const
972 {
973 return lhs < rhs;
974 }
975};
976
977///////////////////////////////////////////////////////////////////////////////
978// (detail) class template invoke_visitor
979//
980// Internal visitor that invokes the given visitor using:
981// * for wrappers (e.g., recursive_wrapper), the wrapper's held value.
982// * for all other values, the value itself.
983//
984template <typename Visitor, bool MoveSemantics>
985class invoke_visitor
986{
987private: // representation
988
989 Visitor& visitor_;
990
991public: // visitor typedefs
992
993 typedef typename Visitor::result_type
994 result_type;
995
996public: // structors
997
998 explicit invoke_visitor(Visitor& visitor) BOOST_NOEXCEPT
999 : visitor_(visitor)
1000 {
1001 }
1002
1003public: // internal visitor interfaces
1004
1005 //using workaround with is_same<T, T> to prenvent compilation error, because we need to use T in enable_if to make SFINAE work
1006 template <typename T>
1007 typename enable_if_c<MoveSemantics && is_same<T, T>::value, result_type>::type internal_visit(T&& operand, int)
1008 {
1009 return visitor_(std::move(operand));
1010 }
1011
1012 //using workaround with is_same<T, T> to prenvent compilation error, because we need to use T in enable_if to make SFINAE work
1013 template <typename T>
1014 typename disable_if_c<MoveSemantics && is_same<T, T>::value, result_type>::type internal_visit(T&& operand, int)
1015 {
1016 return visitor_(operand);
1017 }
1018
1019public: // internal visitor interfaces, cont.
1020
1021 template <typename T>
1022 result_type internal_visit(boost::recursive_wrapper<T>& operand, long)
1023 {
1024 return internal_visit( operand.get(), 1L );
1025 }
1026
1027 template <typename T>
1028 result_type internal_visit(const boost::recursive_wrapper<T>& operand, long)
1029 {
1030 return internal_visit( operand.get(), 1L );
1031 }
1032
1033 template <typename T>
1034 result_type internal_visit(boost::detail::reference_content<T>& operand, long)
1035 {
1036 return internal_visit( operand.get(), 1L );
1037 }
1038
1039 template <typename T>
1040 result_type internal_visit(const boost::detail::reference_content<T>& operand, long)
1041 {
1042 return internal_visit( operand.get(), 1L );
1043 }
1044
1045 template <typename T>
1046 result_type internal_visit(boost::detail::variant::backup_holder<T>& operand, long)
1047 {
1048 return internal_visit( operand.get(), 1L );
1049 }
1050
1051 template <typename T>
1052 result_type internal_visit(const boost::detail::variant::backup_holder<T>& operand, long)
1053 {
1054 return internal_visit( operand.get(), 1L );
1055 }
1056
1057#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
1058private:
1059 // silence MSVC warning C4512: assignment operator could not be generated
1060 invoke_visitor& operator= (invoke_visitor const&);
1061#endif
1062};
1063
1064}} // namespace detail::variant
1065
1066///////////////////////////////////////////////////////////////////////////////
1067// class template variant (concept inspired by Andrei Alexandrescu)
1068//
1069// See docs and boost/variant/variant_fwd.hpp for more information.
1070//
1071template <
1072 typename T0_
1073 , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename T)
1074 >
1075class variant
1076{
1077private: // helpers, for typedefs (below)
1078
1079 typedef variant wknd_self_t;
1080
1081 struct is_recursive_
1082 : detail::variant::is_recursive_flag<T0_>
1083 {
1084 };
1085
1086 typedef typename mpl::eval_if<
1087 is_recursive_
1088 , T0_
1089 , mpl::identity< T0_ >
1090 >::type unwrapped_T0_;
1091
1092 struct is_sequence_based_
1093 : detail::variant::is_over_sequence<unwrapped_T0_>
1094 {
1095 };
1096
1097private: // helpers, for typedefs (below)
1098
1099 typedef typename mpl::eval_if<
1100 is_sequence_based_
1101 , unwrapped_T0_ // over_sequence<...>::type
1102 , detail::variant::make_variant_list<
1103 unwrapped_T0_
1104 , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T)
1105 >
1106 >::type specified_types;
1107
1108 BOOST_STATIC_ASSERT((
1109 ::boost::mpl::not_< mpl::empty<specified_types> >::value
1110 ));
1111
1112public: // public typedefs
1113 typedef typename mpl::eval_if<
1114 is_recursive_
1115 , mpl::transform<
1116 specified_types
1117 , mpl::protect<
1118 detail::variant::quoted_enable_recursive<wknd_self_t>
1119 >
1120 >
1121 , mpl::identity< specified_types >
1122 >::type recursive_enabled_types; // used by is_variant_constructible_from<> trait
1123
1124 typedef typename mpl::transform<
1125 recursive_enabled_types
1126 , unwrap_recursive<mpl::_1>
1127 >::type types;
1128
1129private: // internal typedefs
1130
1131 typedef typename mpl::transform<
1132 recursive_enabled_types
1133 , mpl::protect< detail::make_reference_content<> >
1134 >::type internal_types;
1135
1136 typedef typename mpl::front<
1137 internal_types
1138 >::type internal_T0;
1139
1140private: // helpers, for representation (below)
1141
1142 typedef typename detail::variant::find_fallback_type<
1143 internal_types
1144 >::type fallback_type_result_;
1145
1146 typedef typename fallback_type_result_::first
1147 fallback_type_index_;
1148 typedef typename fallback_type_result_::second
1149 fallback_type_;
1150
1151 struct has_fallback_type_
1152 : mpl::not_<
1153 is_same< fallback_type_, detail::variant::no_fallback_type >
1154 >
1155 {
1156 };
1157
1158 typedef has_fallback_type_
1159 never_uses_backup_flag;
1160
1161 typedef typename detail::variant::make_storage<
1162 internal_types, never_uses_backup_flag
1163 >::type storage_t;
1164
1165 typedef typename detail::variant::is_variant_move_noexcept_constructible<
1166 internal_types
1167 > variant_move_noexcept_constructible;
1168
1169 typedef typename detail::variant::is_variant_move_noexcept_assignable<
1170 internal_types
1171 > variant_move_noexcept_assignable;
1172
1173private: // helpers, for representation (below)
1174
1175 // which_ on:
1176 // * [0, size<internal_types>) indicates stack content
1177 // * [-size<internal_types>, 0) indicates pointer to heap backup
1178 // if which_ >= 0:
1179 // * then which() -> which_
1180 // * else which() -> -(which_ + 1)
1181
1182#if !defined(BOOST_VARIANT_MINIMIZE_SIZE)
1183
1184 typedef int which_t;
1185
1186#else // defined(BOOST_VARIANT_MINIMIZE_SIZE)
1187
1188 // [if O1_size available, then attempt which_t size optimization...]
1189 // [select signed char if fewer than SCHAR_MAX types, else signed int:]
1190 typedef typename mpl::eval_if<
1191 mpl::equal_to< mpl::O1_size<internal_types>, mpl::long_<-1> >
1192 , mpl::identity< int >
1193 , mpl::if_<
1194 mpl::less< mpl::O1_size<internal_types>, mpl::int_<SCHAR_MAX> >
1195 , signed char
1196 , int
1197 >
1198 >::type which_t;
1199
1200#endif // BOOST_VARIANT_MINIMIZE_SIZE switch
1201
1202// representation -- private when possible
1203#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
1204 private:
1205#else
1206 public:
1207#endif
1208
1209 which_t which_;
1210 storage_t storage_;
1211
1212 void indicate_which(int which_arg) BOOST_NOEXCEPT
1213 {
1214 which_ = static_cast<which_t>( which_arg );
1215 }
1216
1217 void indicate_backup_which(int which_arg) BOOST_NOEXCEPT
1218 {
1219 which_ = static_cast<which_t>( -(which_arg + 1) );
1220 }
1221
1222private: // helpers, for queries (below)
1223
1224 bool using_backup() const BOOST_NOEXCEPT
1225 {
1226 return which_ < 0;
1227 }
1228
1229public: // queries
1230
1231 int which() const BOOST_NOEXCEPT
1232 {
1233 // If using heap backup...
1234 if (using_backup())
1235 // ...then return adjusted which_:
1236 return -(which_ + 1);
1237
1238 // Otherwise, return which_ directly:
1239 return which_;
1240 }
1241
1242private: // helpers, for structors (below)
1243
1244 struct initializer
1245 : BOOST_VARIANT_AUX_INITIALIZER_T(
1246 recursive_enabled_types, recursive_enabled_T
1247 )
1248 {
1249 };
1250
1251 void destroy_content() BOOST_NOEXCEPT
1252 {
1253 detail::variant::destroyer visitor;
1254 this->internal_apply_visitor(visitor);
1255 }
1256
1257public: // structors
1258
1259 ~variant() BOOST_NOEXCEPT
1260 {
1261 destroy_content();
1262 }
1263
1264 variant()
1265#if !(defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x5130))
1266 BOOST_NOEXCEPT_IF(boost::has_nothrow_constructor<internal_T0>::value)
1267#endif
1268 {
1269#ifdef _MSC_VER
1270#pragma warning( push )
1271// behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized
1272#pragma warning( disable : 4345 )
1273#endif
1274 // NOTE TO USER :
1275 // Compile error from here indicates that the first bound
1276 // type is not default-constructible, and so variant cannot
1277 // support its own default-construction.
1278 //
1279 new( storage_.address() ) internal_T0();
1280 indicate_which(which_arg: 0); // zero is the index of the first bounded type
1281#ifdef _MSC_VER
1282#pragma warning( pop )
1283#endif
1284 }
1285
1286private: // helpers, for structors, cont. (below)
1287
1288 class convert_copy_into
1289 : public static_visitor<int>
1290 {
1291 private: // representation
1292
1293 void* storage_;
1294
1295 public: // structors
1296
1297 explicit convert_copy_into(void* storage) BOOST_NOEXCEPT
1298 : storage_(storage)
1299 {
1300 }
1301
1302 public: // internal visitor interfaces (below)
1303
1304 template <typename T>
1305 int internal_visit(T& operand, int) const
1306 {
1307 // NOTE TO USER :
1308 // Compile error here indicates one of the source variant's types
1309 // cannot be unambiguously converted to the destination variant's
1310 // types (or that no conversion exists).
1311 //
1312 return initializer::initialize(storage_, operand);
1313 }
1314
1315# if BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x0564))
1316 template <typename T>
1317 result_type internal_visit(const T& operand, int) const
1318 {
1319 return initializer::initialize(storage_, operand);
1320 }
1321# endif
1322
1323 template <typename T>
1324 int internal_visit(boost::detail::reference_content<T>& operand, long) const
1325 {
1326 return internal_visit( operand.get(), 1L );
1327 }
1328
1329 template <typename T>
1330 int internal_visit(const boost::detail::reference_content<T>& operand, long) const
1331 {
1332 return internal_visit( operand.get(), 1L );
1333 }
1334
1335 template <typename T>
1336 int internal_visit(boost::detail::variant::backup_holder<T>& operand, long) const
1337 {
1338 return internal_visit( operand.get(), 1L );
1339 }
1340
1341 template <typename T>
1342 int internal_visit(const boost::detail::variant::backup_holder<T>& operand, long) const
1343 {
1344 return internal_visit( operand.get(), 1L );
1345 }
1346
1347 template <typename T>
1348 int internal_visit(boost::recursive_wrapper<T>& operand, long) const
1349 {
1350 return internal_visit( operand.get(), 1L );
1351 }
1352
1353 template <typename T>
1354 int internal_visit(const boost::recursive_wrapper<T>& operand, long) const
1355 {
1356 return internal_visit( operand.get(), 1L );
1357 }
1358
1359 };
1360
1361 friend class convert_copy_into;
1362
1363 class convert_move_into
1364 : public static_visitor<int>
1365 {
1366 private: // representation
1367
1368 void* storage_;
1369
1370 public: // structors
1371
1372 explicit convert_move_into(void* storage) BOOST_NOEXCEPT
1373 : storage_(storage)
1374 {
1375 }
1376
1377 public: // internal visitor interfaces (below)
1378
1379 template <typename T>
1380 int internal_visit(T& operand, int) const
1381 {
1382 // NOTE TO USER :
1383 // Compile error here indicates one of the source variant's types
1384 // cannot be unambiguously converted to the destination variant's
1385 // types (or that no conversion exists).
1386 //
1387 return initializer::initialize(storage_, detail::variant::move(operand) );
1388 }
1389
1390 template <typename T>
1391 int internal_visit(boost::detail::reference_content<T>& operand, long) const
1392 {
1393 return internal_visit( operand.get(), 1L );
1394 }
1395
1396 template <typename T>
1397 int internal_visit(const boost::detail::reference_content<T>& operand, long) const
1398 {
1399 return internal_visit( operand.get(), 1L );
1400 }
1401
1402 template <typename T>
1403 int internal_visit(boost::detail::variant::backup_holder<T>& operand, long) const
1404 {
1405 return internal_visit( operand.get(), 1L );
1406 }
1407
1408 template <typename T>
1409 int internal_visit(const boost::detail::variant::backup_holder<T>& operand, long) const
1410 {
1411 return internal_visit( operand.get(), 1L );
1412 }
1413
1414 template <typename T>
1415 int internal_visit(boost::recursive_wrapper<T>& operand, long) const
1416 {
1417 return internal_visit( operand.get(), 1L );
1418 }
1419
1420 template <typename T>
1421 int internal_visit(const boost::recursive_wrapper<T>& operand, long) const
1422 {
1423 return internal_visit( operand.get(), 1L );
1424 }
1425 };
1426
1427 friend class convert_move_into;
1428
1429private: // helpers, for structors, below
1430
1431 template <typename T>
1432 void convert_construct(
1433 T& operand
1434 , int
1435 , mpl::false_ = mpl::false_() // is_foreign_variant
1436 )
1437 {
1438 // NOTE TO USER :
1439 // Compile error here indicates that the given type is not
1440 // unambiguously convertible to one of the variant's types
1441 // (or that no conversion exists).
1442 //
1443 indicate_which(
1444 which_arg: initializer::initialize(
1445 storage_.address()
1446 , operand
1447 )
1448 );
1449 }
1450
1451 template <typename T>
1452 typename boost::enable_if<boost::is_rvalue_reference<T&&> >::type convert_construct(
1453 T&& operand
1454 , int
1455 , mpl::false_ = mpl::false_() // is_foreign_variant
1456 )
1457 {
1458 // NOTE TO USER :
1459 // Compile error here indicates that the given type is not
1460 // unambiguously convertible to one of the variant's types
1461 // (or that no conversion exists).
1462 //
1463 indicate_which(
1464 which_arg: initializer::initialize(
1465 storage_.address()
1466 , detail::variant::move(operand)
1467 )
1468 );
1469 }
1470
1471 template <typename Variant>
1472 void convert_construct(
1473 Variant& operand
1474 , long
1475 , mpl::true_// is_foreign_variant
1476 )
1477 {
1478 convert_copy_into visitor(storage_.address());
1479 indicate_which(
1480 which_arg: operand.internal_apply_visitor(visitor)
1481 );
1482 }
1483
1484 template <typename Variant>
1485 typename boost::enable_if<boost::is_rvalue_reference<Variant&&> >::type convert_construct(
1486 Variant&& operand
1487 , long
1488 , mpl::true_// is_foreign_variant
1489 )
1490 {
1491 convert_move_into visitor(storage_.address());
1492 indicate_which(
1493 which_arg: operand.internal_apply_visitor(visitor)
1494 );
1495 }
1496
1497 template <typename Variant>
1498 void convert_construct_variant(Variant& operand)
1499 {
1500 // [Determine if the given variant is itself a bounded type, or if its
1501 // content needs to be converted (i.e., it is a 'foreign' variant):]
1502 //
1503
1504 typedef typename mpl::find_if<
1505 types
1506 , is_same<
1507 add_const<mpl::_1>
1508 , const Variant
1509 >
1510 >::type found_it;
1511
1512 typedef typename mpl::end<types>::type not_found;
1513 typedef typename is_same<
1514 found_it, not_found
1515 >::type is_foreign_variant;
1516
1517 // Convert construct from operand:
1518 convert_construct(
1519 operand, 1L
1520 , is_foreign_variant()
1521 );
1522 }
1523
1524 template <typename Variant>
1525 typename boost::enable_if<boost::is_rvalue_reference<Variant&&> >::type convert_construct_variant(Variant&& operand)
1526 {
1527 // [Determine if the given variant is itself a bounded type, or if its
1528 // content needs to be converted (i.e., it is a 'foreign' variant):]
1529 //
1530
1531 typedef typename mpl::find_if<
1532 types
1533 , is_same<
1534 add_const<mpl::_1>
1535 , const Variant
1536 >
1537 >::type found_it;
1538
1539 typedef typename mpl::end<types>::type not_found;
1540 typedef typename is_same<
1541 found_it, not_found
1542 >::type is_foreign_variant;
1543
1544 // Convert move construct from operand:
1545 convert_construct(
1546 detail::variant::move(operand), 1L
1547 , is_foreign_variant()
1548 );
1549 }
1550
1551 template <BOOST_VARIANT_ENUM_PARAMS(typename U)>
1552 typename boost::enable_if<mpl::or_<
1553 boost::is_same<boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>, variant>,
1554 boost::detail::variant::is_variant_constructible_from<boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>&, internal_types>
1555 > >::type convert_construct(
1556 boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>& operand
1557 , long
1558 )
1559 {
1560 convert_construct_variant(operand);
1561 }
1562
1563 template <BOOST_VARIANT_ENUM_PARAMS(typename U)>
1564 typename boost::enable_if<mpl::or_<
1565 boost::is_same<boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>, variant>,
1566 boost::detail::variant::is_variant_constructible_from<const boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>&, internal_types>
1567 > >::type convert_construct(
1568 const boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>& operand
1569 , long
1570 )
1571 {
1572 convert_construct_variant(operand);
1573 }
1574
1575 template <BOOST_VARIANT_ENUM_PARAMS(typename U)>
1576 typename boost::enable_if<mpl::or_<
1577 boost::is_same<boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>, variant>,
1578 boost::detail::variant::is_variant_constructible_from<boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>&&, internal_types>
1579 > >::type convert_construct(
1580 boost::variant<BOOST_VARIANT_ENUM_PARAMS(U)>&& operand
1581 , long
1582 )
1583 {
1584 convert_construct_variant( detail::variant::move(operand) );
1585 }
1586
1587public: // structors, cont.
1588
1589 template <typename T>
1590 variant(const T& operand,
1591 typename boost::enable_if<mpl::or_<
1592 mpl::and_<
1593 mpl::not_< boost::is_same<T, variant> >,
1594 boost::detail::variant::is_variant_constructible_from<const T&, internal_types>
1595 >,
1596 boost::is_same<T, boost::recursive_variant_> >,
1597 bool >::type = true)
1598 {
1599 convert_construct(operand, 1L);
1600 }
1601
1602 template <typename T>
1603 variant(
1604 T& operand
1605 , typename boost::enable_if<mpl::or_<
1606 mpl::and_<
1607 mpl::not_< is_const<T> >,
1608 mpl::not_< boost::is_same<T, variant> >,
1609 boost::detail::variant::is_variant_constructible_from<T&, internal_types>
1610 >,
1611 boost::is_same<T, boost::recursive_variant_> >,
1612 bool >::type = true
1613 )
1614 {
1615 convert_construct(operand, 1L);
1616 }
1617
1618 template <class T>
1619 variant(T&& operand,
1620 typename boost::enable_if<mpl::or_<
1621 mpl::and_<
1622 boost::is_rvalue_reference<T&&>,
1623 mpl::not_< boost::is_const<T> >,
1624 mpl::not_< boost::is_same<T, variant> >,
1625 boost::detail::variant::is_variant_constructible_from<T&&, internal_types>
1626 >,
1627 boost::is_same<T, boost::recursive_variant_> >,
1628 bool >::type = true)
1629 {
1630 convert_construct( detail::variant::move(operand), 1L);
1631 }
1632
1633public: // structors, cont.
1634
1635 // [MSVC6 requires copy constructor appear after template constructors]
1636 variant(const variant& operand)
1637 {
1638 // Copy the value of operand into *this...
1639 detail::variant::copy_into visitor( storage_.address() );
1640 operand.internal_apply_visitor(visitor);
1641
1642 // ...and activate the *this's primary storage on success:
1643 indicate_which(which_arg: operand.which());
1644 }
1645
1646 variant(variant&& operand) BOOST_NOEXCEPT_IF(variant_move_noexcept_constructible::type::value)
1647 {
1648 // Move the value of operand into *this...
1649 detail::variant::move_into visitor( storage_.address() );
1650 operand.internal_apply_visitor(visitor);
1651
1652 // ...and activate the *this's primary storage on success:
1653 indicate_which(which_arg: operand.which());
1654 }
1655
1656private: // helpers, for modifiers (below)
1657
1658 template <typename Variant>
1659 friend class detail::variant::backup_assigner;
1660
1661 // class assigner
1662 //
1663 // Internal visitor that "assigns" the visited value to the given variant
1664 // by appropriate destruction and copy-construction.
1665 //
1666
1667 class assigner
1668 : public static_visitor<>
1669 {
1670 protected: // representation
1671
1672 variant& lhs_;
1673 const int rhs_which_;
1674
1675 public: // structors
1676
1677 assigner(variant& lhs, int rhs_which) BOOST_NOEXCEPT
1678 : lhs_(lhs)
1679 , rhs_which_(rhs_which)
1680 {
1681 }
1682
1683 protected: // helpers, for internal visitor interface (below)
1684
1685 template <typename RhsT, typename B1, typename B2>
1686 void assign_impl(
1687 const RhsT& rhs_content
1688 , mpl::true_ // has_nothrow_copy
1689 , B1 // is_nothrow_move_constructible
1690 , B2 // has_fallback_type
1691 ) const BOOST_NOEXCEPT
1692 {
1693 // Destroy lhs's content...
1694 lhs_.destroy_content(); // nothrow
1695
1696 // ...copy rhs content into lhs's storage...
1697 new(lhs_.storage_.address())
1698 RhsT( rhs_content ); // nothrow
1699
1700 // ...and indicate new content type:
1701 lhs_.indicate_which(rhs_which_); // nothrow
1702 }
1703
1704 template <typename RhsT, typename B>
1705 void assign_impl(
1706 const RhsT& rhs_content
1707 , mpl::false_ // has_nothrow_copy
1708 , mpl::true_ // is_nothrow_move_constructible
1709 , B // has_fallback_type
1710 ) const
1711 {
1712 // Attempt to make a temporary copy (so as to move it below)...
1713 RhsT temp(rhs_content);
1714
1715 // ...and upon success destroy lhs's content...
1716 lhs_.destroy_content(); // nothrow
1717
1718 // ...move the temporary copy into lhs's storage...
1719 new(lhs_.storage_.address())
1720 RhsT( detail::variant::move(temp) ); // nothrow
1721
1722 // ...and indicate new content type:
1723 lhs_.indicate_which(rhs_which_); // nothrow
1724 }
1725
1726 void construct_fallback() const BOOST_NOEXCEPT {
1727 // In case of failure, default-construct fallback type in lhs's storage...
1728 new (lhs_.storage_.address())
1729 fallback_type_; // nothrow
1730
1731 // ...indicate construction of fallback type...
1732 lhs_.indicate_which(
1733 BOOST_MPL_AUX_VALUE_WKND(fallback_type_index_)::value
1734 ); // nothrow
1735 }
1736
1737 template <typename RhsT>
1738 void assign_impl(
1739 const RhsT& rhs_content
1740 , mpl::false_ // has_nothrow_copy
1741 , mpl::false_ // is_nothrow_move_constructible
1742 , mpl::true_ // has_fallback_type
1743 ) const
1744 {
1745 // Destroy lhs's content...
1746 lhs_.destroy_content(); // nothrow
1747
1748 BOOST_TRY
1749 {
1750 // ...and attempt to copy rhs's content into lhs's storage:
1751 new(lhs_.storage_.address())
1752 RhsT( rhs_content );
1753 }
1754 BOOST_CATCH (...)
1755 {
1756 construct_fallback();
1757
1758 // ...and rethrow:
1759 BOOST_RETHROW;
1760 }
1761 BOOST_CATCH_END
1762
1763 // In the event of success, indicate new content type:
1764 lhs_.indicate_which(rhs_which_); // nothrow
1765 }
1766
1767 template <typename RhsT>
1768 void assign_impl(
1769 const RhsT& rhs_content
1770 , mpl::false_ // has_nothrow_copy
1771 , mpl::false_ // is_nothrow_move_constructible
1772 , mpl::false_ // has_fallback_type
1773 ) const
1774 {
1775 detail::variant::backup_assigner<wknd_self_t>
1776 visitor(lhs_, rhs_which_, rhs_content);
1777 lhs_.internal_apply_visitor(visitor);
1778 }
1779
1780 public: // internal visitor interfaces
1781
1782 template <typename RhsT>
1783 void internal_visit(const RhsT& rhs_content, int) const
1784 {
1785 typedef typename has_nothrow_copy<RhsT>::type
1786 nothrow_copy;
1787 typedef typename mpl::or_< // reduces compile-time
1788 nothrow_copy
1789 , is_nothrow_move_constructible<RhsT>
1790 >::type nothrow_move_constructor;
1791
1792 assign_impl(
1793 rhs_content
1794 , nothrow_copy()
1795 , nothrow_move_constructor()
1796 , has_fallback_type_()
1797 );
1798 }
1799
1800#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
1801 private:
1802 // silence MSVC warning C4512: assignment operator could not be generated
1803 assigner& operator= (assigner const&);
1804#endif
1805 };
1806
1807 friend class assigner;
1808
1809 // class move_assigner
1810 //
1811 // Internal visitor that "move assigns" the visited value to the given variant
1812 // by appropriate destruction and move-construction.
1813 //
1814
1815 class move_assigner
1816 : public assigner
1817 {
1818 public: // structors
1819
1820 move_assigner(variant& lhs, int rhs_which) BOOST_NOEXCEPT
1821 : assigner(lhs, rhs_which)
1822 {
1823 }
1824
1825 private: // helpers, for internal visitor interface (below)
1826
1827 template <typename RhsT, typename B2>
1828 void assign_impl(
1829 RhsT& rhs_content
1830 , mpl::true_ // has_nothrow_copy
1831 , mpl::false_ // is_nothrow_move_constructible
1832 , B2 // has_fallback_type
1833 ) const BOOST_NOEXCEPT
1834 {
1835 assigner::assign_impl(rhs_content, mpl::true_(), mpl::false_(), B2());
1836 }
1837
1838 template <typename RhsT, typename B, typename B2>
1839 void assign_impl(
1840 RhsT& rhs_content
1841 , B // has_nothrow_copy
1842 , mpl::true_ // is_nothrow_move_constructible
1843 , B2 // has_fallback_type
1844 ) const BOOST_NOEXCEPT
1845 {
1846 // ...destroy lhs's content...
1847 assigner::lhs_.destroy_content(); // nothrow
1848
1849 // ...move the rhs_content into lhs's storage...
1850 new(assigner::lhs_.storage_.address())
1851 RhsT( detail::variant::move(rhs_content) ); // nothrow
1852
1853 // ...and indicate new content type:
1854 assigner::lhs_.indicate_which(assigner::rhs_which_); // nothrow
1855 }
1856
1857 template <typename RhsT>
1858 void assign_impl(
1859 RhsT& rhs_content
1860 , mpl::false_ // has_nothrow_copy
1861 , mpl::false_ // is_nothrow_move_constructible
1862 , mpl::true_ // has_fallback_type
1863 ) const
1864 {
1865 // Destroy lhs's content...
1866 assigner::lhs_.destroy_content(); // nothrow
1867
1868 BOOST_TRY
1869 {
1870 // ...and attempt to copy rhs's content into lhs's storage:
1871 new(assigner::lhs_.storage_.address())
1872 RhsT( detail::variant::move(rhs_content) );
1873 }
1874 BOOST_CATCH (...)
1875 {
1876 assigner::construct_fallback();
1877
1878 // ...and rethrow:
1879 BOOST_RETHROW;
1880 }
1881 BOOST_CATCH_END
1882
1883 // In the event of success, indicate new content type:
1884 assigner::lhs_.indicate_which(assigner::rhs_which_); // nothrow
1885 }
1886
1887 template <typename RhsT>
1888 void assign_impl(
1889 RhsT& rhs_content
1890 , mpl::false_ // has_nothrow_copy
1891 , mpl::false_ // is_nothrow_move_constructible
1892 , mpl::false_ // has_fallback_type
1893 ) const
1894 {
1895 assigner::assign_impl(rhs_content, mpl::false_(), mpl::false_(), mpl::false_());
1896 }
1897
1898 public: // internal visitor interfaces
1899
1900 template <typename RhsT>
1901 void internal_visit(RhsT& rhs_content, int) const
1902 {
1903 typedef typename is_nothrow_move_constructible<RhsT>::type
1904 nothrow_move_constructor;
1905 typedef typename mpl::or_< // reduces compile-time
1906 nothrow_move_constructor
1907 , has_nothrow_copy<RhsT>
1908 >::type nothrow_copy;
1909
1910 assign_impl(
1911 rhs_content
1912 , nothrow_copy()
1913 , nothrow_move_constructor()
1914 , has_fallback_type_()
1915 );
1916 }
1917
1918#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
1919 private:
1920 // silence MSVC warning C4512: assignment operator could not be generated
1921 move_assigner& operator= (move_assigner const&);
1922#endif
1923 };
1924
1925 friend class move_assigner;
1926
1927 void variant_assign(const variant& rhs)
1928 {
1929 // If the contained types are EXACTLY the same...
1930 if (which_ == rhs.which_)
1931 {
1932 // ...then assign rhs's storage to lhs's content:
1933 detail::variant::assign_storage visitor(rhs.storage_.address());
1934 this->internal_apply_visitor(visitor);
1935 }
1936 else
1937 {
1938 // Otherwise, perform general (copy-based) variant assignment:
1939 assigner visitor(*this, rhs.which());
1940 rhs.internal_apply_visitor(visitor);
1941 }
1942 }
1943
1944 void variant_assign(variant&& rhs)
1945 {
1946 // If the contained types are EXACTLY the same...
1947 if (which_ == rhs.which_)
1948 {
1949 // ...then move rhs's storage to lhs's content:
1950 detail::variant::move_storage visitor(rhs.storage_.address());
1951 this->internal_apply_visitor(visitor);
1952 }
1953 else
1954 {
1955 // Otherwise, perform general (move-based) variant assignment:
1956 move_assigner visitor(*this, rhs.which());
1957 rhs.internal_apply_visitor(visitor);
1958 }
1959 }
1960
1961private: // helpers, for modifiers (below)
1962
1963 template <typename T>
1964 void assign(const T& rhs)
1965 {
1966 // If direct T-to-T assignment is not possible...
1967 detail::variant::direct_assigner<T> direct_assign(rhs);
1968 if (this->apply_visitor(direct_assign) == false)
1969 {
1970 // ...then convert rhs to variant and assign:
1971 //
1972 // While potentially inefficient, the following construction of a
1973 // variant allows T as any type convertible to one of the bounded
1974 // types without excessive code redundancy.
1975 //
1976 variant temp(rhs);
1977 variant_assign( detail::variant::move(temp) );
1978 }
1979 }
1980
1981 template <typename T>
1982 void move_assign(T&& rhs)
1983 {
1984 // If direct T-to-T move assignment is not possible...
1985 detail::variant::direct_mover<T> direct_move(rhs);
1986 if (this->apply_visitor(direct_move) == false)
1987 {
1988 // ...then convert rhs to variant and assign:
1989 //
1990 // While potentially inefficient, the following construction of a
1991 // variant allows T as any type convertible to one of the bounded
1992 // types without excessive code redundancy.
1993 //
1994 variant temp( detail::variant::move(rhs) );
1995 variant_assign( detail::variant::move(temp) );
1996 }
1997 }
1998
1999public: // modifiers
2000
2001#if !BOOST_WORKAROUND(BOOST_CLANG_VERSION, BOOST_TESTED_AT(150000)) || BOOST_CXX_VERSION <= 202002L
2002 template <class T>
2003 typename boost::enable_if<
2004 boost::mpl::and_<
2005 boost::is_rvalue_reference<T&&>,
2006 mpl::not_< boost::is_const<T> >,
2007 boost::detail::variant::is_variant_constructible_from<T&&, internal_types>
2008 >,
2009 variant&
2010 >::type operator=(T&& rhs)
2011 {
2012 move_assign( detail::variant::move(rhs) );
2013 return *this;
2014 }
2015#endif
2016
2017 template <typename T>
2018 typename boost::enable_if<
2019 mpl::or_<
2020 boost::is_same<T, variant>,
2021 boost::detail::variant::is_variant_constructible_from<const T&, internal_types>
2022 >,
2023 variant&
2024 >::type operator=(const T& rhs)
2025 {
2026 assign(rhs);
2027 return *this;
2028 }
2029
2030 // [MSVC6 requires copy assign appear after templated operator=]
2031 variant& operator=(const variant& rhs)
2032 {
2033 variant_assign(rhs);
2034 return *this;
2035 }
2036
2037 variant& operator=(variant&& rhs)
2038#if !defined(__GNUC__) || (__GNUC__ != 4) || (__GNUC_MINOR__ > 6) || defined(__clang__)
2039 BOOST_NOEXCEPT_IF(variant_move_noexcept_constructible::type::value && variant_move_noexcept_assignable::type::value)
2040#endif
2041 {
2042 variant_assign( detail::variant::move(rhs) );
2043 return *this;
2044 }
2045
2046 void swap(variant& rhs)
2047 {
2048 // If the contained types are the same...
2049 if (which() == rhs.which())
2050 {
2051 // ...then swap the values directly:
2052 detail::variant::swap_with<variant> visitor(rhs);
2053 this->apply_visitor(visitor);
2054 }
2055 else
2056 {
2057 // ...otherwise, perform general variant swap:
2058 variant tmp( detail::variant::move(rhs) );
2059 rhs = detail::variant::move(*this);
2060 *this = detail::variant::move(tmp);
2061 }
2062 }
2063
2064public: // queries
2065
2066 //
2067 // NOTE: member which() defined above.
2068 //
2069
2070 bool empty() const BOOST_NOEXCEPT
2071 {
2072 return false;
2073 }
2074
2075 const boost::typeindex::type_info& type() const
2076 {
2077 detail::variant::reflect visitor;
2078 return this->apply_visitor(visitor);
2079 }
2080
2081public: // prevent comparison with foreign types
2082
2083 template <typename U>
2084 void operator==(const U&) const
2085 {
2086 BOOST_STATIC_ASSERT( false && sizeof(U) );
2087 }
2088
2089 template <typename U>
2090 void operator<(const U&) const
2091 {
2092 BOOST_STATIC_ASSERT( false && sizeof(U) );
2093 }
2094
2095 template <typename U>
2096 void operator!=(const U&) const
2097 {
2098 BOOST_STATIC_ASSERT( false && sizeof(U) );
2099 }
2100
2101 template <typename U>
2102 void operator>(const U&) const
2103 {
2104 BOOST_STATIC_ASSERT( false && sizeof(U) );
2105 }
2106
2107 template <typename U>
2108 void operator<=(const U&) const
2109 {
2110 BOOST_STATIC_ASSERT( false && sizeof(U) );
2111 }
2112
2113 template <typename U>
2114 void operator>=(const U&) const
2115 {
2116 BOOST_STATIC_ASSERT( false && sizeof(U) );
2117 }
2118
2119public: // comparison operators
2120
2121 // [MSVC6 requires these operators appear after template operators]
2122
2123 bool operator==(const variant& rhs) const
2124 {
2125 if (this->which() != rhs.which())
2126 return false;
2127
2128 detail::variant::comparer<
2129 variant, detail::variant::equal_comp
2130 > visitor(*this);
2131 return rhs.apply_visitor(visitor);
2132 }
2133
2134 bool operator<(const variant& rhs) const
2135 {
2136 //
2137 // Dirk Schreib suggested this collating order.
2138 //
2139
2140 if (this->which() != rhs.which())
2141 return this->which() < rhs.which();
2142
2143 detail::variant::comparer<
2144 variant, detail::variant::less_comp
2145 > visitor(*this);
2146 return rhs.apply_visitor(visitor);
2147 }
2148
2149 ///////////////////////////////////////////////////////////////////////////////
2150 // comparison operators != > <= >=
2151 inline bool operator!=(const variant& rhs) const
2152 {
2153 return !(*this == rhs);
2154 }
2155
2156 inline bool operator>(const variant& rhs) const
2157 {
2158 return rhs < *this;
2159 }
2160
2161 inline bool operator<=(const variant& rhs) const
2162 {
2163 return !(*this > rhs);
2164 }
2165
2166 inline bool operator>=(const variant& rhs) const
2167 {
2168 return !(*this < rhs);
2169 }
2170
2171// helpers, for visitation support (below) -- private when possible
2172#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
2173
2174 template < BOOST_VARIANT_ENUM_PARAMS(typename U) >
2175 friend class variant;
2176
2177private:
2178
2179#else// defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
2180
2181public:
2182
2183#endif// !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
2184
2185 template <typename Visitor, typename VoidPtrCV>
2186 BOOST_FORCEINLINE static typename Visitor::result_type
2187 internal_apply_visitor_impl(
2188 int internal_which
2189 , int logical_which
2190 , Visitor& visitor
2191 , VoidPtrCV storage
2192 )
2193 {
2194 typedef mpl::int_<0> first_which;
2195 typedef typename mpl::begin<internal_types>::type first_it;
2196 typedef typename mpl::end<internal_types>::type last_it;
2197
2198 typedef detail::variant::visitation_impl_step<
2199 first_it, last_it
2200 > first_step;
2201
2202 return detail::variant::visitation_impl(
2203 internal_which, logical_which
2204 , visitor, storage, mpl::false_()
2205 , never_uses_backup_flag()
2206 , static_cast<first_which*>(0), static_cast<first_step*>(0)
2207 );
2208 }
2209
2210 template <typename Visitor>
2211 BOOST_FORCEINLINE typename Visitor::result_type
2212 internal_apply_visitor(Visitor& visitor)
2213 {
2214 return internal_apply_visitor_impl(
2215 which_, which(), visitor, storage_.address()
2216 );
2217 }
2218
2219 template <typename Visitor>
2220 BOOST_FORCEINLINE typename Visitor::result_type
2221 internal_apply_visitor(Visitor& visitor) const
2222 {
2223 return internal_apply_visitor_impl(
2224 which_, which(), visitor, storage_.address()
2225 );
2226 }
2227
2228public: // visitation support
2229
2230 template <typename Visitor>
2231 typename Visitor::result_type
2232 apply_visitor(Visitor& visitor) &&
2233 {
2234 detail::variant::invoke_visitor<Visitor, true> invoker(visitor);
2235 return this->internal_apply_visitor(invoker);
2236 }
2237
2238 template <typename Visitor>
2239 typename Visitor::result_type
2240 apply_visitor(Visitor& visitor) const&&
2241 {
2242 detail::variant::invoke_visitor<Visitor, true> invoker(visitor);
2243 return this->internal_apply_visitor(invoker);
2244 }
2245
2246 template <typename Visitor>
2247 typename Visitor::result_type
2248 apply_visitor(Visitor& visitor) &
2249 {
2250 detail::variant::invoke_visitor<Visitor, false> invoker(visitor);
2251 return this->internal_apply_visitor(invoker);
2252 }
2253
2254 template <typename Visitor>
2255 typename Visitor::result_type
2256 apply_visitor(Visitor& visitor) const &
2257 {
2258 detail::variant::invoke_visitor<Visitor, false> invoker(visitor);
2259 return this->internal_apply_visitor(invoker);
2260 }
2261
2262}; // class variant
2263
2264///////////////////////////////////////////////////////////////////////////////
2265// metafunction make_variant_over
2266//
2267// See docs and boost/variant/variant_fwd.hpp for more information.
2268//
2269template <typename Types>
2270struct make_variant_over
2271{
2272private: // precondition assertions
2273
2274 BOOST_STATIC_ASSERT(( ::boost::mpl::is_sequence<Types>::value ));
2275 typedef typename boost::mpl::insert_range<
2276 boost::mpl::list<>
2277 , boost::mpl::end< boost::mpl::list<> >::type
2278 , Types
2279 >::type copied_sequence_t;
2280
2281public: // metafunction result
2282
2283 typedef variant<
2284 detail::variant::over_sequence<copied_sequence_t>
2285 > type;
2286
2287};
2288
2289///////////////////////////////////////////////////////////////////////////////
2290// function template swap
2291//
2292// Swaps two variants of the same type (i.e., identical specification).
2293//
2294template < BOOST_VARIANT_ENUM_PARAMS(typename T) >
2295inline void swap(
2296 variant< BOOST_VARIANT_ENUM_PARAMS(T) >& lhs
2297 , variant< BOOST_VARIANT_ENUM_PARAMS(T) >& rhs
2298 )
2299{
2300 lhs.swap(rhs);
2301}
2302
2303} // namespace boost
2304
2305// implementation additions
2306
2307#if !defined(BOOST_NO_IOSTREAM)
2308#include <boost/variant/detail/variant_io.hpp>
2309#endif // BOOST_NO_IOSTREAM
2310
2311#endif // BOOST_VARIANT_VARIANT_HPP
2312

source code of boost/libs/variant/include/boost/variant/variant.hpp