williamr@2: //----------------------------------------------------------------------------- williamr@2: // boost variant/variant.hpp header file williamr@2: // See http://www.boost.org for updates, documentation, and revision history. williamr@2: //----------------------------------------------------------------------------- williamr@2: // williamr@2: // Copyright (c) 2002-2003 williamr@2: // Eric Friedman, Itay Maman williamr@2: // williamr@2: // Distributed under the Boost Software License, Version 1.0. (See williamr@2: // accompanying file LICENSE_1_0.txt or copy at williamr@2: // http://www.boost.org/LICENSE_1_0.txt) williamr@2: /* williamr@2: * © Portions copyright (c) 2006-2007 Nokia Corporation. All rights reserved. williamr@2: */ williamr@2: #ifndef BOOST_VARIANT_VARIANT_HPP williamr@2: #define BOOST_VARIANT_VARIANT_HPP williamr@2: williamr@2: #include // for std::size_t williamr@2: #include // for placement new williamr@2: #ifdef __SYMBIAN32__ williamr@2: #include williamr@2: #endif williamr@2: #include // for typeid, std::type_info williamr@2: williamr@2: #include "boost/variant/detail/config.hpp" williamr@2: #include "boost/mpl/aux_/config/eti.hpp" williamr@2: #include "boost/mpl/aux_/value_wknd.hpp" williamr@2: williamr@2: #include "boost/variant/variant_fwd.hpp" williamr@2: #include "boost/variant/detail/backup_holder.hpp" williamr@2: #include "boost/variant/detail/enable_recursive_fwd.hpp" williamr@2: #include "boost/variant/detail/forced_return.hpp" williamr@2: #include "boost/variant/detail/initializer.hpp" williamr@2: #include "boost/variant/detail/make_variant_list.hpp" williamr@2: #include "boost/variant/detail/over_sequence.hpp" williamr@2: #include "boost/variant/detail/visitation_impl.hpp" williamr@2: williamr@2: #include "boost/variant/detail/generic_result_type.hpp" williamr@2: #include "boost/variant/detail/has_nothrow_move.hpp" williamr@2: #include "boost/variant/detail/move.hpp" williamr@2: williamr@2: #include "boost/detail/reference_content.hpp" williamr@2: #include "boost/aligned_storage.hpp" williamr@2: #include "boost/blank.hpp" williamr@2: #include "boost/static_assert.hpp" williamr@2: #include "boost/preprocessor/cat.hpp" williamr@2: #include "boost/preprocessor/repeat.hpp" williamr@2: #include "boost/type_traits/alignment_of.hpp" williamr@2: #include "boost/type_traits/add_const.hpp" williamr@2: #include "boost/type_traits/has_nothrow_constructor.hpp" williamr@2: #include "boost/type_traits/has_nothrow_copy.hpp" williamr@2: #include "boost/type_traits/is_const.hpp" williamr@2: #include "boost/type_traits/is_same.hpp" williamr@2: #include "boost/utility/enable_if.hpp" williamr@2: #include "boost/variant/recursive_wrapper_fwd.hpp" williamr@2: #include "boost/variant/static_visitor.hpp" williamr@2: williamr@2: #include "boost/mpl/eval_if.hpp" williamr@2: #include "boost/mpl/begin_end.hpp" williamr@2: #include "boost/mpl/bool.hpp" williamr@2: #include "boost/mpl/empty.hpp" williamr@2: #include "boost/mpl/find_if.hpp" williamr@2: #include "boost/mpl/front.hpp" williamr@2: #include "boost/mpl/identity.hpp" williamr@2: #include "boost/mpl/if.hpp" williamr@2: #include "boost/mpl/int.hpp" williamr@2: #include "boost/mpl/is_sequence.hpp" williamr@2: #include "boost/mpl/iterator_range.hpp" williamr@2: #include "boost/mpl/iter_fold_if.hpp" williamr@2: #include "boost/mpl/logical.hpp" williamr@2: #include "boost/mpl/max_element.hpp" williamr@2: #include "boost/mpl/next.hpp" williamr@2: #include "boost/mpl/deref.hpp" williamr@2: #include "boost/mpl/pair.hpp" williamr@2: #include "boost/mpl/protect.hpp" williamr@2: #include "boost/mpl/push_front.hpp" williamr@2: #include "boost/mpl/same_as.hpp" williamr@2: #include "boost/mpl/size_t.hpp" williamr@2: #include "boost/mpl/sizeof.hpp" williamr@2: #include "boost/mpl/transform.hpp" williamr@2: #include "boost/mpl/assert.hpp" williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // Implementation Macros: williamr@2: // williamr@2: // BOOST_VARIANT_VISITATION_UNROLLING_LIMIT williamr@2: // Defined in boost/variant/detail/visitation_impl.hpp. williamr@2: // williamr@2: // BOOST_VARIANT_MINIMIZE_SIZE williamr@2: // When #defined, implementation employs all known means to minimize the williamr@2: // size of variant obje cts. However, often unsuccessful due to alignment williamr@2: // issues, and potentially harmful to runtime speed, so not enabled by williamr@2: // default. (TODO: Investigate further.) williamr@2: williamr@2: #if defined(BOOST_VARIANT_MINIMIZE_SIZE) williamr@2: # include // for SCHAR_MAX williamr@2: # include "boost/mpl/eval_if.hpp" williamr@2: # include "boost/mpl/equal_to.hpp" williamr@2: # include "boost/mpl/identity.hpp" williamr@2: # include "boost/mpl/int.hpp" williamr@2: # include "boost/mpl/if.hpp" williamr@2: # include "boost/mpl/less.hpp" williamr@2: # include "boost/mpl/long.hpp" williamr@2: # include "boost/mpl/O1_size.hpp" williamr@2: #endif williamr@2: williamr@2: williamr@2: namespace boost { williamr@2: williamr@2: namespace detail { namespace variant { williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) metafunction max_value williamr@2: // williamr@2: // Finds the maximum value of the unary metafunction F over Sequence. williamr@2: // williamr@2: template williamr@2: struct max_value williamr@2: { williamr@2: private: // helpers, for metafunction result (below) williamr@2: williamr@2: typedef typename mpl::transform1::type transformed_; williamr@2: typedef typename mpl::max_element::type max_it; williamr@2: williamr@2: public: // metafunction result williamr@2: williamr@2: typedef typename mpl::deref::type williamr@2: type; williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) metafunction find_fallback_type williamr@2: // williamr@2: // Provides a fallback (i.e., nothrow default-constructible) type from the williamr@2: // specified sequence, or no_fallback_type if not found. williamr@2: // williamr@2: // This implementation is designed to prefer boost::blank over other potential williamr@2: // fallback types, regardless of its position in the specified sequence. williamr@2: // williamr@2: williamr@2: class no_fallback_type; williamr@2: williamr@2: struct find_fallback_type_pred williamr@2: { williamr@2: template williamr@2: struct apply williamr@2: { williamr@2: private: williamr@2: typedef typename mpl::deref::type t_; williamr@2: williamr@2: public: williamr@2: typedef mpl::not_< has_nothrow_constructor > type; williamr@2: }; williamr@2: }; williamr@2: williamr@2: template williamr@2: struct find_fallback_type williamr@2: { williamr@2: private: // helpers, for metafunction result (below) williamr@2: williamr@2: typedef typename mpl::end::type end_it; williamr@2: williamr@2: // [Find the first suitable fallback type...] williamr@2: williamr@2: typedef typename mpl::iter_fold_if< williamr@2: Types williamr@2: , mpl::int_<0>, mpl::protect< mpl::next<> > williamr@2: , mpl::protect< find_fallback_type_pred > williamr@2: >::type first_result_; williamr@2: williamr@2: typedef typename first_result_::first first_result_index; williamr@2: typedef typename first_result_::second first_result_it; williamr@2: williamr@2: // [...now search the rest of the sequence for boost::blank...] williamr@2: williamr@2: typedef typename mpl::iter_fold_if< williamr@2: mpl::iterator_range< first_result_it,end_it > williamr@2: , first_result_index, mpl::protect< mpl::next<> > williamr@2: , mpl::protect< mpl::not_same_as > williamr@2: >::type second_result_; williamr@2: williamr@2: typedef typename second_result_::second second_result_it; williamr@2: williamr@2: public: // metafunction result williamr@2: williamr@2: // [...and return the results of the search:] williamr@2: typedef typename mpl::eval_if< williamr@2: is_same< second_result_it,end_it > williamr@2: , mpl::if_< williamr@2: is_same< first_result_it,end_it > williamr@2: , mpl::pair< no_fallback_type,no_fallback_type > williamr@2: , first_result_ williamr@2: > williamr@2: , mpl::identity< second_result_ > williamr@2: >::type type; williamr@2: williamr@2: }; williamr@2: williamr@2: #if defined(BOOST_MPL_CFG_MSVC_60_ETI_BUG) williamr@2: williamr@2: template<> williamr@2: struct find_fallback_type williamr@2: { williamr@2: typedef mpl::pair< no_fallback_type,no_fallback_type > type; williamr@2: }; williamr@2: williamr@2: #endif // BOOST_MPL_CFG_MSVC_60_ETI_BUG workaround williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) metafunction make_storage williamr@2: // williamr@2: // Provides an aligned storage type capable of holding any of the types williamr@2: // specified in the given type-sequence. williamr@2: // williamr@2: williamr@2: template williamr@2: struct make_storage williamr@2: { williamr@2: private: // helpers, for metafunction result (below) williamr@2: williamr@2: typedef typename mpl::eval_if< williamr@2: NeverUsesBackupFlag williamr@2: , mpl::identity< Types > williamr@2: , mpl::push_front< williamr@2: Types, backup_holder williamr@2: > williamr@2: >::type types; williamr@2: williamr@2: typedef typename max_value< williamr@2: types, mpl::sizeof_ williamr@2: >::type max_size; williamr@2: williamr@2: #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551)) williamr@2: williamr@2: typedef typename max_value< williamr@2: types, alignment_of williamr@2: >::type max_alignment; williamr@2: williamr@2: #else // borland williamr@2: williamr@2: // temporary workaround -- use maximal alignment williamr@2: typedef mpl::size_t< -1 > max_alignment; williamr@2: williamr@2: #endif // borland workaround williamr@2: williamr@2: public: // metafunction result williamr@2: williamr@2: #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) williamr@2: williamr@2: typedef ::boost::aligned_storage< williamr@2: BOOST_MPL_AUX_VALUE_WKND(max_size)::value williamr@2: , BOOST_MPL_AUX_VALUE_WKND(max_alignment)::value williamr@2: > type; williamr@2: williamr@2: #else // MSVC7 and below williamr@2: williamr@2: BOOST_STATIC_CONSTANT(std::size_t, msvc_max_size_c = max_size::value); williamr@2: BOOST_STATIC_CONSTANT(std::size_t, msvc_max_alignment_c = max_alignment::value); williamr@2: williamr@2: typedef ::boost::aligned_storage< williamr@2: msvc_max_size_c williamr@2: , msvc_max_alignment_c williamr@2: > type; williamr@2: williamr@2: #endif // MSVC workaround williamr@2: williamr@2: }; williamr@2: williamr@2: #if defined(BOOST_MPL_CFG_MSVC_60_ETI_BUG) williamr@2: williamr@2: template<> williamr@2: struct make_storage williamr@2: { williamr@2: typedef int type; williamr@2: }; williamr@2: williamr@2: #endif // BOOST_MPL_CFG_MSVC_60_ETI_BUG workaround williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class destroyer williamr@2: // williamr@2: // Internal visitor that destroys the value it visits. williamr@2: // williamr@2: struct destroyer williamr@2: : public static_visitor<> williamr@2: { williamr@2: public: // visitor interfaces williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: internal_visit(T& operand, int) const williamr@2: { williamr@2: operand.~T(); williamr@2: williamr@2: #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551)) williamr@2: operand; // suppresses warnings williamr@2: #endif williamr@2: williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class template known_get williamr@2: // williamr@2: // Visitor that returns a reference to content of the specified type. williamr@2: // williamr@2: // Precondition: visited variant MUST contain logical content of type T. williamr@2: // williamr@2: template williamr@2: class known_get williamr@2: : public static_visitor williamr@2: { williamr@2: williamr@2: #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) williamr@2: williamr@2: public: // visitor interface williamr@2: williamr@2: T& operator()(T& operand) const williamr@2: { williamr@2: return operand; williamr@2: } williamr@2: williamr@2: template williamr@2: T& operator()(U&) const williamr@2: { williamr@2: // logical error to be here: see precondition above williamr@2: BOOST_ASSERT(false); williamr@2: return ::boost::detail::variant::forced_return< T& >(); williamr@2: } williamr@2: williamr@2: #else // MSVC6 williamr@2: williamr@2: private: // helpers, for visitor interface (below) williamr@2: williamr@2: T& execute(T& operand, mpl::true_) const williamr@2: { williamr@2: return operand; williamr@2: } williamr@2: williamr@2: template williamr@2: T& execute(U& operand, mpl::false_) const williamr@2: { williamr@2: // logical error to be here: see precondition above williamr@2: BOOST_ASSERT(false); williamr@2: return ::boost::detail::variant::forced_return< T& >(); williamr@2: } williamr@2: williamr@2: public: // visitor interface williamr@2: williamr@2: template williamr@2: T& operator()(U& operand) const williamr@2: { williamr@2: typedef typename is_same< U,T >::type williamr@2: U_is_T; williamr@2: williamr@2: return execute(operand, U_is_T()); williamr@2: } williamr@2: williamr@2: #endif // MSVC6 workaround williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class copy_into williamr@2: // williamr@2: // Internal visitor that copies the value it visits into the given buffer. williamr@2: // williamr@2: class copy_into williamr@2: : public static_visitor<> williamr@2: { williamr@2: private: // representation williamr@2: williamr@2: void* storage_; williamr@2: williamr@2: public: // structors williamr@2: williamr@2: explicit copy_into(void* storage) williamr@2: : storage_(storage) williamr@2: { williamr@2: } williamr@2: williamr@2: public: // internal visitor interface williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: internal_visit(boost::detail::variant::backup_holder& operand, long) const williamr@2: { williamr@2: new(storage_) T( operand.get() ); williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: internal_visit(const boost::detail::variant::backup_holder& operand, long) const williamr@2: { williamr@2: new(storage_) T( operand.get() ); williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: internal_visit(const T& operand, int) const williamr@2: { williamr@2: new(storage_) T(operand); williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class assign_storage williamr@2: // williamr@2: // Internal visitor that assigns the given storage (which must be a williamr@2: // constructed value of the same type) to the value it visits. williamr@2: // williamr@2: struct assign_storage williamr@2: : public static_visitor<> williamr@2: { williamr@2: private: // representation williamr@2: williamr@2: const void* rhs_storage_; williamr@2: williamr@2: public: // structors williamr@2: williamr@2: explicit assign_storage(const void* rhs_storage) williamr@2: : rhs_storage_(rhs_storage) williamr@2: { williamr@2: } williamr@2: williamr@2: public: // internal visitor interfaces williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: internal_visit(backup_holder& lhs_content, long) const williamr@2: { williamr@2: lhs_content.get() williamr@2: = static_cast< const backup_holder* >(rhs_storage_)->get(); williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: internal_visit(const backup_holder& lhs_content, long) const williamr@2: { williamr@2: lhs_content.get() williamr@2: = static_cast< const backup_holder* >(rhs_storage_)->get(); williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: internal_visit(T& lhs_content, int) const williamr@2: { williamr@2: // NOTE TO USER : williamr@2: // Compile error here indicates one of variant's bounded types does williamr@2: // not meet the requirements of the Assignable concept. Thus, williamr@2: // variant is not Assignable. williamr@2: // williamr@2: // Hint: Are any of the bounded types const-qualified or references? williamr@2: // williamr@2: lhs_content = *static_cast< const T* >(rhs_storage_); williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class direct_assigner williamr@2: // williamr@2: // Generic static visitor that: if and only if the visited value is of the williamr@2: // specified type, assigns the given value to the visited value and returns williamr@2: // true; else returns false. williamr@2: // williamr@2: template williamr@2: class direct_assigner williamr@2: : public static_visitor williamr@2: { williamr@2: private: // representation williamr@2: williamr@2: T& rhs_; williamr@2: williamr@2: public: // structors williamr@2: williamr@2: explicit direct_assigner(T& rhs) williamr@2: : rhs_(rhs) williamr@2: { williamr@2: } williamr@2: williamr@2: #if !BOOST_WORKAROUND(BOOST_MSVC, < 1300) williamr@2: williamr@2: public: // visitor interface williamr@2: williamr@2: bool operator()(T& lhs) williamr@2: { williamr@2: lhs = rhs_; williamr@2: return true; williamr@2: } williamr@2: williamr@2: template williamr@2: bool operator()(U&) williamr@2: { williamr@2: return false; williamr@2: } williamr@2: williamr@2: #else // MSVC6 williamr@2: williamr@2: private: // helpers, for visitor interface (below) williamr@2: williamr@2: bool execute(T& lhs, mpl::true_) williamr@2: { williamr@2: lhs = rhs_; williamr@2: return true; williamr@2: } williamr@2: williamr@2: template williamr@2: bool execute(U&, mpl::false_) williamr@2: { williamr@2: return false; williamr@2: } williamr@2: williamr@2: public: // visitor interface williamr@2: williamr@2: template williamr@2: bool operator()(U& lhs) williamr@2: { williamr@2: typedef typename is_same::type U_is_T; williamr@2: return execute(lhs, U_is_T()); williamr@2: } williamr@2: williamr@2: #endif // MSVC6 workaround williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class backup_assigner williamr@2: // williamr@2: // Internal visitor that "assigns" the given value to the visited value, williamr@2: // using backup to recover if the destroy-copy sequence fails. williamr@2: // williamr@2: // NOTE: This needs to be a friend of variant, as it needs access to williamr@2: // indicate_which, indicate_backup_which, etc. williamr@2: // williamr@2: template williamr@2: class backup_assigner williamr@2: : public static_visitor<> williamr@2: { williamr@2: private: // representation williamr@2: williamr@2: Variant& lhs_; williamr@2: int rhs_which_; williamr@2: const RhsT& rhs_content_; williamr@2: williamr@2: public: // structors williamr@2: williamr@2: backup_assigner(Variant& lhs, int rhs_which, const RhsT& rhs_content) williamr@2: : lhs_(lhs) williamr@2: , rhs_which_(rhs_which) williamr@2: , rhs_content_(rhs_content) williamr@2: { williamr@2: } williamr@2: williamr@2: private: // helpers, for visitor interface (below) williamr@2: williamr@2: template williamr@2: void backup_assign_impl( williamr@2: LhsT& lhs_content williamr@2: , mpl::true_// has_nothrow_move williamr@2: ) williamr@2: { williamr@2: // Move lhs content to backup... williamr@2: LhsT backup_lhs_content( williamr@2: ::boost::detail::variant::move(lhs_content) williamr@2: ); // nothrow williamr@2: williamr@2: // ...destroy lhs content... williamr@2: lhs_content.~LhsT(); // nothrow williamr@2: williamr@2: try williamr@2: { williamr@2: // ...and attempt to copy rhs content into lhs storage: williamr@2: new(lhs_.storage_.address()) RhsT(rhs_content_); williamr@2: } williamr@2: catch (...) williamr@2: { williamr@2: // In case of failure, restore backup content to lhs storage... williamr@2: new(lhs_.storage_.address()) williamr@2: LhsT( williamr@2: ::boost::detail::variant::move(backup_lhs_content) williamr@2: ); // nothrow williamr@2: williamr@2: // ...and rethrow: williamr@2: throw; williamr@2: } williamr@2: williamr@2: // In case of success, indicate new content type: williamr@2: lhs_.indicate_which(rhs_which_); // nothrow williamr@2: } williamr@2: williamr@2: template williamr@2: void backup_assign_impl( williamr@2: LhsT& lhs_content williamr@2: , mpl::false_// has_nothrow_move williamr@2: ) williamr@2: { williamr@2: // Backup lhs content... williamr@2: LhsT* backup_lhs_ptr = new LhsT(lhs_content); williamr@2: williamr@2: // ...destroy lhs content... williamr@2: lhs_content.~LhsT(); // nothrow williamr@2: williamr@2: try williamr@2: { williamr@2: // ...and attempt to copy rhs content into lhs storage: williamr@2: new(lhs_.storage_.address()) RhsT(rhs_content_); williamr@2: } williamr@2: catch (...) williamr@2: { williamr@2: // In case of failure, copy backup pointer to lhs storage... williamr@2: new(lhs_.storage_.address()) williamr@2: backup_holder( backup_lhs_ptr ); // nothrow williamr@2: williamr@2: // ...indicate now using backup... williamr@2: lhs_.indicate_backup_which( lhs_.which() ); // nothrow williamr@2: williamr@2: // ...and rethrow: williamr@2: throw; williamr@2: } williamr@2: williamr@2: // In case of success, indicate new content type... williamr@2: lhs_.indicate_which(rhs_which_); // nothrow williamr@2: williamr@2: // ...and delete backup: williamr@2: delete backup_lhs_ptr; // nothrow williamr@2: } williamr@2: williamr@2: public: // visitor interface williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: internal_visit(LhsT& lhs_content, int) williamr@2: { williamr@2: typedef typename has_nothrow_move_constructor::type williamr@2: nothrow_move; williamr@2: williamr@2: backup_assign_impl( lhs_content, nothrow_move() ); williamr@2: williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class swap_with williamr@2: // williamr@2: // Visitor that swaps visited value with content of given variant. williamr@2: // williamr@2: // Precondition: Given variant MUST have same logical type as visited value. williamr@2: // williamr@2: template williamr@2: struct swap_with williamr@2: : public static_visitor<> williamr@2: { williamr@2: private: // representation williamr@2: williamr@2: Variant& toswap_; williamr@2: williamr@2: public: // structors williamr@2: williamr@2: explicit swap_with(Variant& toswap) williamr@2: : toswap_(toswap) williamr@2: { williamr@2: } williamr@2: williamr@2: public: // internal visitor interfaces williamr@2: williamr@2: template williamr@2: void operator()(T& operand) const williamr@2: { williamr@2: // Since the precondition ensures types are same, get T... williamr@2: known_get getter; williamr@2: T& other = toswap_.apply_visitor(getter); williamr@2: williamr@2: // ...and swap: williamr@2: ::boost::detail::variant::move_swap( operand, other ); williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class reflect williamr@2: // williamr@2: // Generic static visitor that performs a typeid on the value it visits. williamr@2: // williamr@2: class reflect williamr@2: : public static_visitor williamr@2: { williamr@2: public: // visitor interfaces williamr@2: williamr@2: template williamr@2: const std::type_info& operator()(const T&) const williamr@2: { williamr@2: return typeid(T); williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class comparer williamr@2: // williamr@2: // Generic static visitor that compares the content of the given lhs variant williamr@2: // with the visited rhs content using Comp. williamr@2: // williamr@2: // Precondition: lhs.which() == rhs.which() williamr@2: // williamr@2: template williamr@2: class comparer williamr@2: : public static_visitor williamr@2: { williamr@2: private: // representation williamr@2: williamr@2: const Variant& lhs_; williamr@2: williamr@2: public: // structors williamr@2: williamr@2: explicit comparer(const Variant& lhs) williamr@2: : lhs_(lhs) williamr@2: { williamr@2: } williamr@2: williamr@2: public: // visitor interfaces williamr@2: williamr@2: template williamr@2: bool operator()(const T& rhs_content) const williamr@2: { williamr@2: // Since the precondition ensures lhs and rhs types are same, get T... williamr@2: known_get getter; williamr@2: const T& lhs_content = lhs_.apply_visitor(getter); williamr@2: williamr@2: // ...and compare lhs and rhs contents: williamr@2: return Comp()(lhs_content, rhs_content); williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class equal_comp williamr@2: // williamr@2: // Generic function object compares lhs with rhs using operator==. williamr@2: // williamr@2: struct equal_comp williamr@2: { williamr@2: template williamr@2: bool operator()(const T& lhs, const T& rhs) const williamr@2: { williamr@2: return lhs == rhs; williamr@2: } williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class less_comp williamr@2: // williamr@2: // Generic function object compares lhs with rhs using operator<. williamr@2: // williamr@2: struct less_comp williamr@2: { williamr@2: template williamr@2: bool operator()(const T& lhs, const T& rhs) const williamr@2: { williamr@2: return lhs < rhs; williamr@2: } williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // (detail) class template invoke_visitor williamr@2: // williamr@2: // Internal visitor that invokes the given visitor using: williamr@2: // * for wrappers (e.g., recursive_wrapper), the wrapper's held value. williamr@2: // * for all other values, the value itself. williamr@2: // williamr@2: template williamr@2: class invoke_visitor williamr@2: { williamr@2: private: // representation williamr@2: williamr@2: Visitor& visitor_; williamr@2: williamr@2: public: // visitor typedefs williamr@2: williamr@2: typedef typename Visitor::result_type williamr@2: result_type; williamr@2: williamr@2: public: // structors williamr@2: williamr@2: explicit invoke_visitor(Visitor& visitor) williamr@2: : visitor_(visitor) williamr@2: { williamr@2: } williamr@2: williamr@2: #if !defined(BOOST_NO_VOID_RETURNS) williamr@2: williamr@2: public: // internal visitor interfaces williamr@2: williamr@2: template williamr@2: result_type internal_visit(T& operand, int) williamr@2: { williamr@2: return visitor_(operand); williamr@2: } williamr@2: williamr@2: # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) williamr@2: template williamr@2: result_type internal_visit(const T& operand, int) williamr@2: { williamr@2: return visitor_(operand); williamr@2: } williamr@2: # endif williamr@2: williamr@2: #else // defined(BOOST_NO_VOID_RETURNS) williamr@2: williamr@2: private: // helpers, for internal visitor interfaces (below) williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) williamr@2: visit_impl(T& operand, mpl::false_) williamr@2: { williamr@2: return visitor_(operand); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: visit_impl(T& operand, mpl::true_) williamr@2: { williamr@2: visitor_(operand); williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: public: // internal visitor interfaces williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) williamr@2: internal_visit(T& operand, int) williamr@2: { williamr@2: typedef typename is_same::type williamr@2: has_void_result_type; williamr@2: williamr@2: return visit_impl(operand, has_void_result_type()); williamr@2: } williamr@2: williamr@2: #endif // BOOST_NO_VOID_RETURNS) workaround williamr@2: williamr@2: public: // internal visitor interfaces, cont. williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) williamr@2: internal_visit(boost::recursive_wrapper& operand, long) williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) williamr@2: internal_visit(const boost::recursive_wrapper& operand, long) williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) williamr@2: internal_visit(boost::detail::reference_content& operand, long) williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) williamr@2: internal_visit(const boost::detail::reference_content& operand, long) williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) williamr@2: internal_visit(boost::detail::variant::backup_holder& operand, long) williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE(result_type) williamr@2: internal_visit(const boost::detail::variant::backup_holder& operand, long) williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: }} // namespace detail::variant williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // class template variant (concept inspired by Andrei Alexandrescu) williamr@2: // williamr@2: // See docs and boost/variant/variant_fwd.hpp for more information. williamr@2: // williamr@2: template < williamr@2: typename T0_ williamr@2: , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(typename T) williamr@2: > williamr@2: class variant williamr@2: { williamr@2: private: // helpers, for typedefs (below) williamr@2: williamr@2: typedef variant wknd_self_t; williamr@2: williamr@2: struct is_recursive_ williamr@2: : detail::variant::is_recursive_flag williamr@2: { williamr@2: }; williamr@2: williamr@2: typedef typename mpl::eval_if< williamr@2: is_recursive_ williamr@2: , T0_ williamr@2: , mpl::identity< T0_ > williamr@2: >::type unwrapped_T0_; williamr@2: williamr@2: struct is_sequence_based_ williamr@2: : detail::variant::is_over_sequence williamr@2: { williamr@2: }; williamr@2: williamr@2: #if !defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) williamr@2: williamr@2: private: // helpers, for typedefs (below) williamr@2: williamr@2: typedef typename mpl::eval_if< williamr@2: is_sequence_based_ williamr@2: , unwrapped_T0_ // over_sequence<...>::type williamr@2: , detail::variant::make_variant_list< williamr@2: unwrapped_T0_ williamr@2: , BOOST_VARIANT_ENUM_SHIFTED_PARAMS(T) williamr@2: > williamr@2: >::type specified_types; williamr@2: williamr@2: BOOST_STATIC_ASSERT(( williamr@2: ::boost::mpl::not_< mpl::empty >::value williamr@2: )); williamr@2: williamr@2: typedef typename mpl::eval_if< williamr@2: is_recursive_ williamr@2: , mpl::transform< williamr@2: specified_types williamr@2: , mpl::protect< williamr@2: detail::variant::quoted_enable_recursive williamr@2: > williamr@2: > williamr@2: , mpl::identity< specified_types > williamr@2: >::type recursive_enabled_types; williamr@2: williamr@2: public: // public typedefs williamr@2: williamr@2: typedef typename mpl::transform< williamr@2: recursive_enabled_types williamr@2: , unwrap_recursive williamr@2: >::type types; williamr@2: williamr@2: private: // internal typedefs williamr@2: williamr@2: typedef typename mpl::transform< williamr@2: recursive_enabled_types williamr@2: , mpl::protect< detail::make_reference_content<> > williamr@2: >::type internal_types; williamr@2: williamr@2: typedef typename mpl::front< williamr@2: internal_types williamr@2: >::type internal_T0; williamr@2: williamr@2: #else // defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) williamr@2: williamr@2: private: // helpers, for typedefs (below) williamr@2: williamr@2: typedef unwrapped_T0_ T0; williamr@2: williamr@2: #define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS(z,N,_) \ williamr@2: typedef typename mpl::eval_if< \ williamr@2: is_recursive_ \ williamr@2: , detail::variant::enable_recursive< \ williamr@2: BOOST_PP_CAT(T,N) \ williamr@2: , wknd_self_t \ williamr@2: > \ williamr@2: , mpl::identity< BOOST_PP_CAT(T,N) > \ williamr@2: >::type BOOST_PP_CAT(recursive_enabled_T,N); \ williamr@2: /**/ williamr@2: williamr@2: BOOST_PP_REPEAT( williamr@2: BOOST_VARIANT_LIMIT_TYPES williamr@2: , BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS williamr@2: , _ williamr@2: ) williamr@2: williamr@2: #undef BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS williamr@2: williamr@2: #define BOOST_VARIANT_AUX_UNWRAP_RECURSIVE_TYPEDEFS(z,N,_) \ williamr@2: typedef typename unwrap_recursive< \ williamr@2: BOOST_PP_CAT(recursive_enabled_T,N) \ williamr@2: >::type BOOST_PP_CAT(public_T,N); \ williamr@2: /**/ williamr@2: williamr@2: BOOST_PP_REPEAT( williamr@2: BOOST_VARIANT_LIMIT_TYPES williamr@2: , BOOST_VARIANT_AUX_UNWRAP_RECURSIVE_TYPEDEFS williamr@2: , _ williamr@2: ) williamr@2: williamr@2: #undef BOOST_VARIANT_AUX_UNWRAP_RECURSIVE_TYPEDEFS williamr@2: williamr@2: public: // public typedefs williamr@2: williamr@2: typedef typename detail::variant::make_variant_list< williamr@2: BOOST_VARIANT_ENUM_PARAMS(public_T) williamr@2: >::type types; williamr@2: williamr@2: private: // helpers, for internal typedefs (below) williamr@2: williamr@2: #define BOOST_VARIANT_AUX_MAKE_REFERENCE_CONTENT_TYPEDEFS(z,N,_) \ williamr@2: typedef detail::make_reference_content< \ williamr@2: BOOST_PP_CAT(recursive_enabled_T,N) \ williamr@2: >::type BOOST_PP_CAT(internal_T,N); \ williamr@2: /**/ williamr@2: williamr@2: BOOST_PP_REPEAT( williamr@2: BOOST_VARIANT_LIMIT_TYPES williamr@2: , BOOST_VARIANT_AUX_MAKE_REFERENCE_CONTENT_TYPEDEFS williamr@2: , _ williamr@2: ) williamr@2: williamr@2: #undef BOOST_VARIANT_AUX_MAKE_REFERENCE_CONTENT_TYPEDEFS williamr@2: williamr@2: private: // internal typedefs williamr@2: williamr@2: typedef typename detail::variant::make_variant_list< williamr@2: BOOST_VARIANT_ENUM_PARAMS(internal_T) williamr@2: >::type internal_types; williamr@2: williamr@2: private: // static precondition assertions williamr@2: williamr@2: // NOTE TO USER : williamr@2: // variant< type-sequence > syntax is not supported on this compiler! williamr@2: // williamr@2: BOOST_MPL_ASSERT_NOT(( is_sequence_based_ )); williamr@2: williamr@2: #endif // BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT workaround williamr@2: williamr@2: private: // helpers, for representation (below) williamr@2: williamr@2: typedef typename detail::variant::find_fallback_type< williamr@2: internal_types williamr@2: >::type fallback_type_result_; williamr@2: williamr@2: typedef typename fallback_type_result_::first williamr@2: fallback_type_index_; williamr@2: typedef typename fallback_type_result_::second williamr@2: fallback_type_; williamr@2: williamr@2: struct has_fallback_type_ williamr@2: : mpl::not_< williamr@2: is_same< fallback_type_, detail::variant::no_fallback_type > williamr@2: > williamr@2: { williamr@2: }; williamr@2: williamr@2: typedef has_fallback_type_ williamr@2: never_uses_backup_flag; williamr@2: williamr@2: typedef typename detail::variant::make_storage< williamr@2: internal_types, never_uses_backup_flag williamr@2: >::type storage_t; williamr@2: williamr@2: private: // helpers, for representation (below) williamr@2: williamr@2: // which_ on: williamr@2: // * [0, size) indicates stack content williamr@2: // * [-size, 0) indicates pointer to heap backup williamr@2: // if which_ >= 0: williamr@2: // * then which() -> which_ williamr@2: // * else which() -> -(which_ + 1) williamr@2: williamr@2: #if !defined(BOOST_VARIANT_MINIMIZE_SIZE) williamr@2: williamr@2: typedef int which_t; williamr@2: williamr@2: #else // defined(BOOST_VARIANT_MINIMIZE_SIZE) williamr@2: williamr@2: // [if O1_size available, then attempt which_t size optimization...] williamr@2: // [select signed char if fewer than SCHAR_MAX types, else signed int:] williamr@2: typedef typename mpl::eval_if< williamr@2: mpl::equal_to< mpl::O1_size, mpl::long_<-1> > williamr@2: , mpl::identity< int > williamr@2: , mpl::if_< williamr@2: mpl::less< mpl::O1_size, mpl::int_ > williamr@2: , signed char williamr@2: , int williamr@2: > williamr@2: >::type which_t; williamr@2: williamr@2: #endif // BOOST_VARIANT_MINIMIZE_SIZE switch williamr@2: williamr@2: // representation -- private when possible williamr@2: #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) williamr@2: private: williamr@2: #else williamr@2: public: williamr@2: #endif williamr@2: williamr@2: which_t which_; williamr@2: storage_t storage_; williamr@2: williamr@2: void indicate_which(int which) williamr@2: { williamr@2: which_ = static_cast( which ); williamr@2: } williamr@2: williamr@2: void indicate_backup_which(int which) williamr@2: { williamr@2: which_ = static_cast( -(which + 1) ); williamr@2: } williamr@2: williamr@2: private: // helpers, for queries (below) williamr@2: williamr@2: bool using_backup() const williamr@2: { williamr@2: return which_ < 0; williamr@2: } williamr@2: williamr@2: public: // queries williamr@2: williamr@2: int which() const williamr@2: { williamr@2: // If using heap backup... williamr@2: if (using_backup()) williamr@2: // ...then return adjusted which_: williamr@2: return -(which_ + 1); williamr@2: williamr@2: // Otherwise, return which_ directly: williamr@2: return which_; williamr@2: } williamr@2: williamr@2: private: // helpers, for structors (below) williamr@2: williamr@2: struct initializer williamr@2: : BOOST_VARIANT_AUX_INITIALIZER_T( williamr@2: recursive_enabled_types, recursive_enabled_T williamr@2: ) williamr@2: { williamr@2: }; williamr@2: williamr@2: void destroy_content() williamr@2: { williamr@2: detail::variant::destroyer visitor; williamr@2: this->internal_apply_visitor(visitor); williamr@2: } williamr@2: williamr@2: public: // structors williamr@2: williamr@2: ~variant() williamr@2: { williamr@2: destroy_content(); williamr@2: } williamr@2: williamr@2: variant() williamr@2: { williamr@2: // NOTE TO USER : williamr@2: // Compile error from here indicates that the first bound williamr@2: // type is not default-constructible, and so variant cannot williamr@2: // support its own default-construction. williamr@2: // williamr@2: new( storage_.address() ) internal_T0(); williamr@2: indicate_which(0); // zero is the index of the first bounded type williamr@2: } williamr@2: williamr@2: private: // helpers, for structors, cont. (below) williamr@2: williamr@2: class convert_copy_into williamr@2: : public static_visitor williamr@2: { williamr@2: private: // representation williamr@2: williamr@2: void* storage_; williamr@2: williamr@2: public: // structors williamr@2: williamr@2: explicit convert_copy_into(void* storage) williamr@2: : storage_(storage) williamr@2: { williamr@2: } williamr@2: williamr@2: public: // internal visitor interfaces (below) williamr@2: williamr@2: template williamr@2: int internal_visit(T& operand, int) const williamr@2: { williamr@2: // NOTE TO USER : williamr@2: // Compile error here indicates one of the source variant's types williamr@2: // cannot be unambiguously converted to the destination variant's williamr@2: // types (or that no conversion exists). williamr@2: // williamr@2: return initializer::initialize(storage_, operand); williamr@2: } williamr@2: williamr@2: # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0564)) williamr@2: template williamr@2: result_type internal_visit(const T& operand, int) const williamr@2: { williamr@2: return initializer::initialize(storage_, operand); williamr@2: } williamr@2: # endif williamr@2: williamr@2: template williamr@2: int internal_visit(boost::detail::reference_content& operand, long) const williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: int internal_visit(const boost::detail::reference_content& operand, long) const williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: int internal_visit(boost::detail::variant::backup_holder& operand, long) const williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: int internal_visit(const boost::detail::variant::backup_holder& operand, long) const williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: int internal_visit(boost::recursive_wrapper& operand, long) const williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: template williamr@2: int internal_visit(const boost::recursive_wrapper& operand, long) const williamr@2: { williamr@2: return internal_visit( operand.get(), 1L ); williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: friend class convert_copy_into; williamr@2: williamr@2: private: // helpers, for structors, below williamr@2: williamr@2: template williamr@2: void convert_construct( williamr@2: T& operand williamr@2: , int williamr@2: , mpl::false_ = mpl::false_() // is_foreign_variant williamr@2: ) williamr@2: { williamr@2: // NOTE TO USER : williamr@2: // Compile error here indicates that the given type is not williamr@2: // unambiguously convertible to one of the variant's types williamr@2: // (or that no conversion exists). williamr@2: // williamr@2: indicate_which( williamr@2: initializer::initialize( williamr@2: storage_.address() williamr@2: , operand williamr@2: ) williamr@2: ); williamr@2: } williamr@2: williamr@2: template williamr@2: void convert_construct( williamr@2: Variant& operand williamr@2: , long williamr@2: , mpl::true_// is_foreign_variant williamr@2: ) williamr@2: { williamr@2: convert_copy_into visitor(storage_.address()); williamr@2: indicate_which( williamr@2: operand.internal_apply_visitor(visitor) williamr@2: ); williamr@2: } williamr@2: williamr@2: template williamr@2: void convert_construct_variant(Variant& operand) williamr@2: { williamr@2: // [Determine if the given variant is itself a bounded type, or if its williamr@2: // content needs to be converted (i.e., it is a 'foreign' variant):] williamr@2: // williamr@2: williamr@2: typedef typename mpl::find_if< williamr@2: types williamr@2: , is_same< williamr@2: add_const williamr@2: , const Variant williamr@2: > williamr@2: >::type found_it; williamr@2: williamr@2: typedef typename mpl::end::type not_found; williamr@2: typedef typename is_same< williamr@2: found_it, not_found williamr@2: >::type is_foreign_variant; williamr@2: williamr@2: // Convert construct from operand: williamr@2: convert_construct( williamr@2: operand, 1L williamr@2: , is_foreign_variant() williamr@2: ); williamr@2: } williamr@2: williamr@2: template williamr@2: void convert_construct( williamr@2: boost::variant& operand williamr@2: , long williamr@2: ) williamr@2: { williamr@2: convert_construct_variant(operand); williamr@2: } williamr@2: williamr@2: template williamr@2: void convert_construct( williamr@2: const boost::variant& operand williamr@2: , long williamr@2: ) williamr@2: { williamr@2: convert_construct_variant(operand); williamr@2: } williamr@2: williamr@2: public: // structors, cont. williamr@2: williamr@2: #if !defined(BOOST_VARIANT_AUX_BROKEN_CONSTRUCTOR_TEMPLATE_ORDERING) williamr@2: williamr@2: template williamr@2: variant(const T& operand) williamr@2: { williamr@2: convert_construct(operand, 1L); williamr@2: } williamr@2: williamr@2: template williamr@2: variant(T& operand) williamr@2: { williamr@2: convert_construct(operand, 1L); williamr@2: } williamr@2: williamr@2: #elif defined(BOOST_VARIANT_AUX_HAS_CONSTRUCTOR_TEMPLATE_ORDERING_SFINAE_WKND) williamr@2: williamr@2: // For compilers that cannot distinguish between T& and const T& in williamr@2: // template constructors, but do fully support SFINAE, we can workaround: williamr@2: williamr@2: template williamr@2: variant(const T& operand) williamr@2: { williamr@2: convert_construct(operand, 1L); williamr@2: } williamr@2: williamr@2: template williamr@2: variant( williamr@2: T& operand williamr@2: , typename enable_if< williamr@2: mpl::not_< is_const > williamr@2: , void williamr@2: >::type* = 0 williamr@2: ) williamr@2: { williamr@2: convert_construct(operand, 1L); williamr@2: } williamr@2: williamr@2: #else // !defined(BOOST_VARIANT_AUX_HAS_CONSTRUCTOR_TEMPLATE_ORDERING_SFINAE_WKND) williamr@2: williamr@2: // For compilers that cannot distinguish between T& and const T& in williamr@2: // template constructors, and do NOT support SFINAE, we can't workaround: williamr@2: williamr@2: template williamr@2: variant(const T& operand) williamr@2: { williamr@2: convert_construct(operand, 1L); williamr@2: } williamr@2: williamr@2: #endif // BOOST_VARIANT_AUX_BROKEN_CONSTRUCTOR_TEMPLATE_ORDERING workarounds williamr@2: williamr@2: public: // structors, cont. williamr@2: williamr@2: // [MSVC6 requires copy constructor appear after template constructors] williamr@2: variant(const variant& operand) williamr@2: { williamr@2: // Copy the value of operand into *this... williamr@2: detail::variant::copy_into visitor( storage_.address() ); williamr@2: operand.internal_apply_visitor(visitor); williamr@2: williamr@2: // ...and activate the *this's primary storage on success: williamr@2: indicate_which(operand.which()); williamr@2: } williamr@2: williamr@2: private: // helpers, for modifiers (below) williamr@2: williamr@2: # if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) williamr@2: template williamr@2: friend class detail::variant::backup_assigner; williamr@2: # endif williamr@2: williamr@2: // class assigner williamr@2: // williamr@2: // Internal visitor that "assigns" the visited value to the given variant williamr@2: // by appropriate destruction and copy-construction. williamr@2: // williamr@2: williamr@2: class assigner williamr@2: : public static_visitor<> williamr@2: { williamr@2: private: // representation williamr@2: williamr@2: variant& lhs_; williamr@2: int rhs_which_; williamr@2: williamr@2: public: // structors williamr@2: williamr@2: assigner(variant& lhs, int rhs_which) williamr@2: : lhs_(lhs) williamr@2: , rhs_which_(rhs_which) williamr@2: { williamr@2: } williamr@2: williamr@2: private: // helpers, for internal visitor interface (below) williamr@2: williamr@2: template williamr@2: void assign_impl( williamr@2: const RhsT& rhs_content williamr@2: , mpl::true_// has_nothrow_copy williamr@2: , B1// has_nothrow_move_constructor williamr@2: , B2// has_fallback_type williamr@2: ) williamr@2: { williamr@2: // Destroy lhs's content... williamr@2: lhs_.destroy_content(); // nothrow williamr@2: williamr@2: // ...copy rhs content into lhs's storage... williamr@2: new(lhs_.storage_.address()) williamr@2: RhsT( rhs_content ); // nothrow williamr@2: williamr@2: // ...and indicate new content type: williamr@2: lhs_.indicate_which(rhs_which_); // nothrow williamr@2: } williamr@2: williamr@2: template williamr@2: void assign_impl( williamr@2: const RhsT& rhs_content williamr@2: , mpl::false_// has_nothrow_copy williamr@2: , mpl::true_// has_nothrow_move_constructor williamr@2: , B// has_fallback_type williamr@2: ) williamr@2: { williamr@2: // Attempt to make a temporary copy (so as to move it below)... williamr@2: RhsT temp(rhs_content); williamr@2: williamr@2: // ...and upon success destroy lhs's content... williamr@2: lhs_.destroy_content(); // nothrow williamr@2: williamr@2: // ...move the temporary copy into lhs's storage... williamr@2: new(lhs_.storage_.address()) williamr@2: RhsT( detail::variant::move(temp) ); // nothrow williamr@2: williamr@2: // ...and indicate new content type: williamr@2: lhs_.indicate_which(rhs_which_); // nothrow williamr@2: } williamr@2: williamr@2: template williamr@2: void assign_impl( williamr@2: const RhsT& rhs_content williamr@2: , mpl::false_// has_nothrow_copy williamr@2: , mpl::false_// has_nothrow_move_constructor williamr@2: , mpl::true_// has_fallback_type williamr@2: ) williamr@2: { williamr@2: // Destroy lhs's content... williamr@2: lhs_.destroy_content(); // nothrow williamr@2: williamr@2: try williamr@2: { williamr@2: // ...and attempt to copy rhs's content into lhs's storage: williamr@2: new(lhs_.storage_.address()) williamr@2: RhsT( rhs_content ); williamr@2: } williamr@2: catch (...) williamr@2: { williamr@2: // In case of failure, default-construct fallback type in lhs's storage... williamr@2: new (lhs_.storage_.address()) williamr@2: fallback_type_; // nothrow williamr@2: williamr@2: // ...indicate construction of fallback type... williamr@2: lhs_.indicate_which( williamr@2: BOOST_MPL_AUX_VALUE_WKND(fallback_type_index_)::value williamr@2: ); // nothrow williamr@2: williamr@2: // ...and rethrow: williamr@2: throw; williamr@2: } williamr@2: williamr@2: // In the event of success, indicate new content type: williamr@2: lhs_.indicate_which(rhs_which_); // nothrow williamr@2: } williamr@2: williamr@2: template williamr@2: void assign_impl( williamr@2: const RhsT& rhs_content williamr@2: , mpl::false_// has_nothrow_copy williamr@2: , mpl::false_// has_nothrow_move_constructor williamr@2: , mpl::false_// has_fallback_type williamr@2: ) williamr@2: { williamr@2: detail::variant::backup_assigner williamr@2: visitor(lhs_, rhs_which_, rhs_content); williamr@2: lhs_.internal_apply_visitor(visitor); williamr@2: } williamr@2: williamr@2: public: // internal visitor interfaces williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_RETURN_VOID_TYPE williamr@2: internal_visit(const RhsT& rhs_content, int) williamr@2: { williamr@2: typedef typename has_nothrow_copy::type williamr@2: nothrow_copy; williamr@2: typedef typename mpl::or_< // reduces compile-time williamr@2: nothrow_copy williamr@2: , detail::variant::has_nothrow_move_constructor williamr@2: >::type nothrow_move_constructor; williamr@2: williamr@2: assign_impl( williamr@2: rhs_content williamr@2: , nothrow_copy() williamr@2: , nothrow_move_constructor() williamr@2: , has_fallback_type_() williamr@2: ); williamr@2: williamr@2: BOOST_VARIANT_AUX_RETURN_VOID; williamr@2: } williamr@2: williamr@2: }; williamr@2: williamr@2: friend class assigner; williamr@2: williamr@2: void variant_assign(const variant& rhs) williamr@2: { williamr@2: // If the contained types are EXACTLY the same... williamr@2: if (which_ == rhs.which_) williamr@2: { williamr@2: // ...then assign rhs's storage to lhs's content: williamr@2: detail::variant::assign_storage visitor(rhs.storage_.address()); williamr@2: this->internal_apply_visitor(visitor); williamr@2: } williamr@2: else williamr@2: { williamr@2: // Otherwise, perform general (copy-based) variant assignment: williamr@2: assigner visitor(*this, rhs.which()); williamr@2: rhs.internal_apply_visitor(visitor); williamr@2: } williamr@2: } williamr@2: williamr@2: private: // helpers, for modifiers (below) williamr@2: williamr@2: template williamr@2: void assign(const T& rhs) williamr@2: { williamr@2: // If direct T-to-T assignment is not possible... williamr@2: detail::variant::direct_assigner direct_assign(rhs); williamr@2: if (this->apply_visitor(direct_assign) == false) williamr@2: { williamr@2: // ...then convert rhs to variant and assign: williamr@2: // williamr@2: // While potentially inefficient, the following construction of a williamr@2: // variant allows T as any type convertible to one of the bounded williamr@2: // types without excessive code redundancy. williamr@2: // williamr@2: variant temp(rhs); williamr@2: variant_assign( detail::variant::move(temp) ); williamr@2: } williamr@2: } williamr@2: williamr@2: public: // modifiers williamr@2: williamr@2: template williamr@2: variant& operator=(const T& rhs) williamr@2: { williamr@2: assign(rhs); williamr@2: return *this; williamr@2: } williamr@2: williamr@2: // [MSVC6 requires copy assign appear after templated operator=] williamr@2: variant& operator=(const variant& rhs) williamr@2: { williamr@2: variant_assign(rhs); williamr@2: return *this; williamr@2: } williamr@2: williamr@2: void swap(variant& rhs) williamr@2: { williamr@2: // If the contained types are the same... williamr@2: if (which() == rhs.which()) williamr@2: { williamr@2: // ...then swap the values directly: williamr@2: detail::variant::swap_with visitor(rhs); williamr@2: this->apply_visitor(visitor); williamr@2: } williamr@2: else williamr@2: { williamr@2: // ...otherwise, perform general variant swap: williamr@2: variant tmp( detail::variant::move(rhs) ); williamr@2: rhs = detail::variant::move(*this); williamr@2: *this = detail::variant::move(tmp); williamr@2: } williamr@2: } williamr@2: williamr@2: public: // queries williamr@2: williamr@2: // williamr@2: // NOTE: member which() defined above. williamr@2: // williamr@2: williamr@2: bool empty() const williamr@2: { williamr@2: return false; williamr@2: } williamr@2: williamr@2: const std::type_info& type() const williamr@2: { williamr@2: detail::variant::reflect visitor; williamr@2: return this->apply_visitor(visitor); williamr@2: } williamr@2: williamr@2: public: // prevent comparison with foreign types williamr@2: williamr@2: #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) williamr@2: williamr@2: # define BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE \ williamr@2: void williamr@2: williamr@2: #else // MSVC7 williamr@2: williamr@2: // williamr@2: // MSVC7 gives error about return types for above being different than williamr@2: // the true comparison operator overloads: williamr@2: // williamr@2: williamr@2: # define BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE \ williamr@2: bool williamr@2: williamr@2: #endif // MSVC7 workaround williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE williamr@2: operator==(const U&) const williamr@2: { williamr@2: BOOST_STATIC_ASSERT( false && sizeof(U) ); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_FAIL_COMPARISON_RETURN_TYPE williamr@2: operator<(const U&) const williamr@2: { williamr@2: BOOST_STATIC_ASSERT( false && sizeof(U) ); williamr@2: } williamr@2: williamr@2: public: // comparison operators williamr@2: williamr@2: // [MSVC6 requires these operators appear after template operators] williamr@2: williamr@2: bool operator==(const variant& rhs) const williamr@2: { williamr@2: if (this->which() != rhs.which()) williamr@2: return false; williamr@2: williamr@2: detail::variant::comparer< williamr@2: variant, detail::variant::equal_comp williamr@2: > visitor(*this); williamr@2: return rhs.apply_visitor(visitor); williamr@2: } williamr@2: williamr@2: bool operator<(const variant& rhs) const williamr@2: { williamr@2: // williamr@2: // Dirk Schreib suggested this collating order. williamr@2: // williamr@2: williamr@2: if (this->which() != rhs.which()) williamr@2: return this->which() < rhs.which(); williamr@2: williamr@2: detail::variant::comparer< williamr@2: variant, detail::variant::less_comp williamr@2: > visitor(*this); williamr@2: return rhs.apply_visitor(visitor); williamr@2: } williamr@2: williamr@2: // helpers, for visitation support (below) -- private when possible williamr@2: #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) williamr@2: williamr@2: template < BOOST_VARIANT_ENUM_PARAMS(typename U) > williamr@2: friend class variant; williamr@2: williamr@2: private: williamr@2: williamr@2: #else// defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) williamr@2: williamr@2: public: williamr@2: williamr@2: #endif// !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) williamr@2: williamr@2: template williamr@2: static williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( williamr@2: typename Visitor::result_type williamr@2: ) williamr@2: internal_apply_visitor_impl( williamr@2: int internal_which williamr@2: , int logical_which williamr@2: , Visitor& visitor williamr@2: , VoidPtrCV storage williamr@2: ) williamr@2: { williamr@2: typedef mpl::int_<0> first_which; williamr@2: typedef typename mpl::begin::type first_it; williamr@2: typedef typename mpl::end::type last_it; williamr@2: williamr@2: typedef detail::variant::visitation_impl_step< williamr@2: first_it, last_it williamr@2: > first_step; williamr@2: williamr@2: return detail::variant::visitation_impl( williamr@2: internal_which, logical_which williamr@2: , visitor, storage, mpl::false_() williamr@2: , never_uses_backup_flag() williamr@2: , static_cast(0), static_cast(0) williamr@2: ); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( williamr@2: typename Visitor::result_type williamr@2: ) williamr@2: internal_apply_visitor(Visitor& visitor) williamr@2: { williamr@2: return internal_apply_visitor_impl( williamr@2: which_, which(), visitor, storage_.address() williamr@2: ); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( williamr@2: typename Visitor::result_type williamr@2: ) williamr@2: internal_apply_visitor(Visitor& visitor) const williamr@2: { williamr@2: return internal_apply_visitor_impl( williamr@2: which_, which(), visitor, storage_.address() williamr@2: ); williamr@2: } williamr@2: williamr@2: public: // visitation support williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( williamr@2: typename Visitor::result_type williamr@2: ) williamr@2: apply_visitor(Visitor& visitor) williamr@2: { williamr@2: detail::variant::invoke_visitor invoker(visitor); williamr@2: return this->internal_apply_visitor(invoker); williamr@2: } williamr@2: williamr@2: template williamr@2: BOOST_VARIANT_AUX_GENERIC_RESULT_TYPE( williamr@2: typename Visitor::result_type williamr@2: ) williamr@2: apply_visitor(Visitor& visitor) const williamr@2: { williamr@2: detail::variant::invoke_visitor invoker(visitor); williamr@2: return this->internal_apply_visitor(invoker); williamr@2: } williamr@2: williamr@2: }; // class variant williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // metafunction make_variant_over williamr@2: // williamr@2: // See docs and boost/variant/variant_fwd.hpp for more information. williamr@2: // williamr@2: template williamr@2: struct make_variant_over williamr@2: { williamr@2: private: // precondition assertions williamr@2: williamr@2: #if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) williamr@2: BOOST_STATIC_ASSERT(( ::boost::mpl::is_sequence::value )); williamr@2: #endif williamr@2: williamr@2: public: // metafunction result williamr@2: williamr@2: typedef variant< williamr@2: detail::variant::over_sequence< Types > williamr@2: > type; williamr@2: williamr@2: }; williamr@2: williamr@2: /////////////////////////////////////////////////////////////////////////////// williamr@2: // function template swap williamr@2: // williamr@2: // Swaps two variants of the same type (i.e., identical specification). williamr@2: // williamr@2: template < BOOST_VARIANT_ENUM_PARAMS(typename T) > williamr@2: inline void swap( williamr@2: variant< BOOST_VARIANT_ENUM_PARAMS(T) >& lhs williamr@2: , variant< BOOST_VARIANT_ENUM_PARAMS(T) >& rhs williamr@2: ) williamr@2: { williamr@2: lhs.swap(rhs); williamr@2: } williamr@2: williamr@2: } // namespace boost williamr@2: williamr@2: // implementation additions williamr@2: #include "boost/variant/detail/variant_io.hpp" williamr@2: williamr@2: #endif // BOOST_VARIANT_VARIANT_HPP