diff --git a/include/boost/variant.hpp b/include/boost/variant.hpp index 24ef3f9..99e4401 100644 --- a/include/boost/variant.hpp +++ b/include/boost/variant.hpp @@ -22,6 +22,7 @@ #include "boost/variant/variant.hpp" // common applications +#include "boost/variant/recursive_variant.hpp" #include "boost/variant/get.hpp" #include "boost/variant/apply_visitor.hpp" #include "boost/variant/static_visitor.hpp" diff --git a/include/boost/variant/recursive_variant.hpp b/include/boost/variant/recursive_variant.hpp new file mode 100644 index 0000000..0171ad2 --- /dev/null +++ b/include/boost/variant/recursive_variant.hpp @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// boost variant/recursive_variant.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman +// +// Permission to use, copy, modify, distribute and sell this software +// and its documentation for any purpose is hereby granted without fee, +// provided that the above copyright notice appears in all copies and +// that both the copyright notice and this permission notice appear in +// supporting documentation. No representations are made about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. + +#ifndef BOOST_VARIANT_RECURSIVE_VARIANT_HPP +#define BOOST_VARIANT_RECURSIVE_VARIANT_HPP + +#include "boost/incomplete.hpp" // only forward-declared in variant.hpp +#include "boost/mpl/arg.hpp" + +namespace boost { + +typedef mpl::arg<1> recursive_variant; + +} // namespace boost + +#endif // BOOST_VARIANT_RECURSIVE_VARIANT_HPP diff --git a/include/boost/variant/variant.hpp b/include/boost/variant/variant.hpp index 6429e62..d8c24fb 100644 --- a/include/boost/variant/variant.hpp +++ b/include/boost/variant/variant.hpp @@ -48,11 +48,11 @@ #include "boost/type_traits/is_same.hpp" #include "boost/variant/static_visitor.hpp" +#include "boost/mpl/apply.hpp" #include "boost/mpl/apply_if.hpp" #include "boost/mpl/begin_end.hpp" #include "boost/mpl/bool.hpp" #include "boost/mpl/contains.hpp" -#include "boost/mpl/count_if.hpp" #include "boost/mpl/distance.hpp" #include "boost/mpl/empty.hpp" #include "boost/mpl/equal_to.hpp" @@ -61,6 +61,8 @@ #include "boost/mpl/int.hpp" #include "boost/mpl/is_sequence.hpp" #include "boost/mpl/iter_fold.hpp" +#include "boost/mpl/front.hpp" +#include "boost/mpl/lambda.hpp" #include "boost/mpl/list.hpp" #include "boost/mpl/logical.hpp" #include "boost/mpl/max_element.hpp" @@ -601,6 +603,56 @@ public: // static functions #endif // !defined(BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE) +/////////////////////////////////////////////////////////////////////////////// +// (detail) metafunction enable_recursive +// +// Enables the boost::variant<..., boost::recursive_variant, ...> syntax. +// + +template +struct rebind1 +{ +private: + typedef typename mpl::lambda< + mpl::identity + >::type le_; + +public: + typedef typename mpl::apply_if< + is_same< le_, mpl::identity > + , le_ // identity + , mpl::apply1 + >::type type; +}; + +template +struct enable_recursive +{ +private: // helpers, for metafunction result (below) + + typedef typename rebind1::type t_; + +public: // metafunction result + + // [Wrap with incomplete only if rebind really changed something:] + typedef typename mpl::if_< + is_same< t_, T > + , t_ + , boost::incomplete + >::type type; + +}; + +template +struct quoted_enable_recursive +{ + template + struct apply + : enable_recursive + { + }; +}; + /////////////////////////////////////////////////////////////////////////////// // (detail) function template cast_storage // @@ -764,47 +816,65 @@ apply_visitor_impl( // See docs and boost/variant/variant_fwd.hpp for more information. // template < -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551)) BOOST_VARIANT_ENUM_PARAMS(typename T_) -#else - BOOST_VARIANT_ENUM_PARAMS(typename T) -#endif > class variant { -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551)) - -private: - - // borland seemingly cannot use template arguments within class scope, - // so we define the following typedefs to workaround: - #define BOOST_VARIANT_AUX_BORLAND_TYPEDEFS(z,N,_) \ - typedef BOOST_PP_CAT(T_,N) BOOST_PP_CAT(T,N); \ - /**/ - BOOST_PP_REPEAT( - BOOST_VARIANT_LIMIT_TYPES - , BOOST_VARIANT_AUX_BORLAND_TYPEDEFS - , _ - ) - #undef BOOST_VARIANT_AUX_BORLAND_TYPEDEFS - -#endif // borland workaround - #if !defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) +private: // helpers, for typedefs (below) + + typedef typename mpl::apply_if< + mpl::is_sequence + , mpl::identity + , detail::variant::make_variant_list< + BOOST_VARIANT_ENUM_PARAMS(T_) + > + >::type plain_nonrecursive_types; + public: // typedefs - typedef typename mpl::apply_if< - mpl::is_sequence - , mpl::identity - , detail::variant::make_variant_list< - BOOST_VARIANT_ENUM_PARAMS(T) - > + typedef typename mpl::transform< + plain_nonrecursive_types + , mpl::protect< detail::variant::quoted_enable_recursive > >::type types; +private: // private typedefs + + typedef typename mpl::front::type T0; + #else // defined(BOOST_VARIANT_NO_TYPE_SEQUENCE_SUPPORT) +private: // helpers, for typedefs (below) + +# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1200) + + typedef variant wknd_self_t; + + #define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS(z,N,_) \ + typedef typename detail::variant::enable_recursive< \ + BOOST_PP_CAT(T_,N) \ + , wknd_self_t \ + >::type BOOST_PP_CAT(T,N); \ + /**/ + +# else // MSVC6 + + #define BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS(z,N,_) \ + typedef BOOST_PP_CAT(T_,N) BOOST_PP_CAT(T,N); \ + /**/ + +# endif // MSVC6 workaround + + BOOST_PP_REPEAT( + BOOST_VARIANT_LIMIT_TYPES + , BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS + , _ + ) + + #undef BOOST_VARIANT_AUX_ENABLE_RECURSIVE_TYPEDEFS + public: // typedefs typedef typename detail::variant::make_variant_list< @@ -824,6 +894,7 @@ private: // static precondition assertions # else // MSVC6 + // for some reason, msvc needs following all on one line: BOOST_STATIC_CONSTANT(bool, msvc_not_is_sequence_T0 = mpl::not_< mpl::is_sequence >::value); BOOST_STATIC_ASSERT(msvc_not_is_sequence_T0);