Chris@102: //----------------------------------------------------------------------------- Chris@102: // boost variant/polymorphic_get.hpp header file Chris@102: // See http://www.boost.org for updates, documentation, and revision history. Chris@102: //----------------------------------------------------------------------------- Chris@102: // Chris@102: // Copyright (c) 2013-2015 Antony Polukhin Chris@102: // Chris@102: // Distributed under the Boost Software License, Version 1.0. (See Chris@102: // accompanying file LICENSE_1_0.txt or copy at Chris@102: // http://www.boost.org/LICENSE_1_0.txt) Chris@102: Chris@102: #ifndef BOOST_VARIANT_POLYMORPHIC_GET_HPP Chris@102: #define BOOST_VARIANT_POLYMORPHIC_GET_HPP Chris@102: Chris@102: #include Chris@102: Chris@102: #include "boost/config.hpp" Chris@102: #include "boost/detail/workaround.hpp" Chris@102: #include "boost/static_assert.hpp" Chris@102: #include "boost/throw_exception.hpp" Chris@102: #include "boost/utility/addressof.hpp" Chris@102: #include "boost/variant/variant_fwd.hpp" Chris@102: #include "boost/variant/get.hpp" Chris@102: Chris@102: #include "boost/type_traits/add_reference.hpp" Chris@102: #include "boost/type_traits/add_pointer.hpp" Chris@102: #include "boost/type_traits/is_base_of.hpp" Chris@102: Chris@102: namespace boost { Chris@102: Chris@102: ////////////////////////////////////////////////////////////////////////// Chris@102: // class bad_polymorphic_get Chris@102: // Chris@102: // The exception thrown in the event of a failed get of a value. Chris@102: // Chris@102: class BOOST_SYMBOL_VISIBLE bad_polymorphic_get Chris@102: : public bad_get Chris@102: { Chris@102: public: // std::exception implementation Chris@102: Chris@102: virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW Chris@102: { Chris@102: return "boost::bad_polymorphic_get: " Chris@102: "failed value get using boost::polymorphic_get"; Chris@102: } Chris@102: Chris@102: }; Chris@102: Chris@102: ////////////////////////////////////////////////////////////////////////// Chris@102: // function template get Chris@102: // Chris@102: // Retrieves content of given variant object if content is of type T. Chris@102: // Otherwise: pointer ver. returns 0; reference ver. throws bad_get. Chris@102: // Chris@102: Chris@102: namespace detail { namespace variant { Chris@102: Chris@102: Chris@102: /////////////////////////////////////////////////////////////////////////////////////////////////// Chris@102: // polymorphic metafunctions to detect index of a value Chris@102: // Chris@102: Chris@102: template Chris@102: struct element_polymorphic_iterator_impl : Chris@102: boost::mpl::find_if< Chris@102: Types, Chris@102: boost::mpl::or_< Chris@102: variant_element_functor, Chris@102: variant_element_functor::type >, Chris@102: boost::is_base_of Chris@102: > Chris@102: > Chris@102: {}; Chris@102: Chris@102: template Chris@102: struct holds_element_polymorphic : Chris@102: boost::mpl::not_< Chris@102: boost::is_same< Chris@102: typename boost::mpl::end::type, Chris@102: typename element_polymorphic_iterator_impl::type Chris@102: > Chris@102: > Chris@102: {}; Chris@102: Chris@102: // (detail) class template get_polymorphic_visitor Chris@102: // Chris@102: // Generic static visitor that: if the value is of the specified Chris@102: // type or of a type derived from specified, returns a pointer Chris@102: // to the value it visits; else a null pointer. Chris@102: // Chris@102: template Chris@102: struct get_polymorphic_visitor Chris@102: { Chris@102: private: // private typedefs Chris@102: typedef get_polymorphic_visitor this_type; Chris@102: typedef typename add_pointer::type pointer; Chris@102: typedef typename add_reference::type reference; Chris@102: Chris@102: pointer get(reference operand, boost::true_type) const BOOST_NOEXCEPT Chris@102: { Chris@102: return boost::addressof(operand); Chris@102: } Chris@102: Chris@102: template Chris@102: pointer get(T&, boost::false_type) const BOOST_NOEXCEPT Chris@102: { Chris@102: return static_cast(0); Chris@102: } Chris@102: Chris@102: public: // visitor interfaces Chris@102: typedef pointer result_type; Chris@102: Chris@102: template Chris@102: pointer operator()(U& operand) const BOOST_NOEXCEPT Chris@102: { Chris@102: typedef boost::integral_constant< Chris@102: bool, Chris@102: boost::mpl::or_< Chris@102: boost::is_base_of, Chris@102: boost::is_same, Chris@102: boost::is_same::type, U > Chris@102: >::value Chris@102: > tag_t; Chris@102: Chris@102: return this_type::get(operand, tag_t()); Chris@102: } Chris@102: }; Chris@102: Chris@102: }} // namespace detail::variant Chris@102: Chris@102: #ifndef BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE Chris@102: # if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0551)) Chris@102: # define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t) Chris@102: # else Chris@102: # define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t) \ Chris@102: , t* = 0 Chris@102: # endif Chris@102: #endif Chris@102: Chris@102: ////////////////////////////////////////////////////////////////////////////////////////////////////////// Chris@102: // polymorphic_relaxed_get Chris@102: // Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_pointer::type Chris@102: polymorphic_relaxed_get( Chris@102: boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) BOOST_NOEXCEPT Chris@102: { Chris@102: typedef typename add_pointer::type U_ptr; Chris@102: if (!operand) return static_cast(0); Chris@102: Chris@102: detail::variant::get_polymorphic_visitor v; Chris@102: return operand->apply_visitor(v); Chris@102: } Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_pointer::type Chris@102: polymorphic_relaxed_get( Chris@102: const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) BOOST_NOEXCEPT Chris@102: { Chris@102: typedef typename add_pointer::type U_ptr; Chris@102: if (!operand) return static_cast(0); Chris@102: Chris@102: detail::variant::get_polymorphic_visitor v; Chris@102: return operand->apply_visitor(v); Chris@102: } Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_reference::type Chris@102: polymorphic_relaxed_get( Chris@102: boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) Chris@102: { Chris@102: typedef typename add_pointer::type U_ptr; Chris@102: U_ptr result = polymorphic_relaxed_get(&operand); Chris@102: Chris@102: if (!result) Chris@102: boost::throw_exception(bad_polymorphic_get()); Chris@102: return *result; Chris@102: } Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_reference::type Chris@102: polymorphic_relaxed_get( Chris@102: const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) Chris@102: { Chris@102: typedef typename add_pointer::type U_ptr; Chris@102: U_ptr result = polymorphic_relaxed_get(&operand); Chris@102: Chris@102: if (!result) Chris@102: boost::throw_exception(bad_polymorphic_get()); Chris@102: return *result; Chris@102: } Chris@102: Chris@102: ////////////////////////////////////////////////////////////////////////////////////////////////////////// Chris@102: // polymorphic_strict_get Chris@102: // Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_pointer::type Chris@102: polymorphic_strict_get( Chris@102: boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) BOOST_NOEXCEPT Chris@102: { Chris@102: BOOST_STATIC_ASSERT_MSG( Chris@102: (boost::detail::variant::holds_element_polymorphic, U >::value), Chris@102: "boost::variant does not contain specified type U, " Chris@102: "call to boost::polymorphic_get(boost::variant*) will always return NULL" Chris@102: ); Chris@102: Chris@102: return polymorphic_relaxed_get(operand); Chris@102: } Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_pointer::type Chris@102: polymorphic_strict_get( Chris@102: const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) BOOST_NOEXCEPT Chris@102: { Chris@102: BOOST_STATIC_ASSERT_MSG( Chris@102: (boost::detail::variant::holds_element_polymorphic, U >::value), Chris@102: "boost::variant does not contain specified type U, " Chris@102: "call to boost::polymorphic_get(const boost::variant*) will always return NULL" Chris@102: ); Chris@102: Chris@102: return polymorphic_relaxed_get(operand); Chris@102: } Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_reference::type Chris@102: polymorphic_strict_get( Chris@102: boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) Chris@102: { Chris@102: BOOST_STATIC_ASSERT_MSG( Chris@102: (boost::detail::variant::holds_element_polymorphic, U >::value), Chris@102: "boost::variant does not contain specified type U, " Chris@102: "call to boost::polymorphic_get(boost::variant&) will always throw boost::bad_polymorphic_get exception" Chris@102: ); Chris@102: Chris@102: return polymorphic_relaxed_get(operand); Chris@102: } Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_reference::type Chris@102: polymorphic_strict_get( Chris@102: const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) Chris@102: { Chris@102: BOOST_STATIC_ASSERT_MSG( Chris@102: (boost::detail::variant::holds_element_polymorphic, U >::value), Chris@102: "boost::variant does not contain specified type U, " Chris@102: "call to boost::polymorphic_get(const boost::variant&) will always throw boost::bad_polymorphic_get exception" Chris@102: ); Chris@102: Chris@102: return polymorphic_relaxed_get(operand); Chris@102: } Chris@102: Chris@102: ///////////////////////////////////////////////////////////////////////////////////////////////////////////// Chris@102: // polymorphic_get(variant) methods Chris@102: // Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_pointer::type Chris@102: polymorphic_get( Chris@102: boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) BOOST_NOEXCEPT Chris@102: { Chris@102: #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT Chris@102: return polymorphic_relaxed_get(operand); Chris@102: #else Chris@102: return polymorphic_strict_get(operand); Chris@102: #endif Chris@102: Chris@102: } Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_pointer::type Chris@102: polymorphic_get( Chris@102: const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) BOOST_NOEXCEPT Chris@102: { Chris@102: #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT Chris@102: return polymorphic_relaxed_get(operand); Chris@102: #else Chris@102: return polymorphic_strict_get(operand); Chris@102: #endif Chris@102: } Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_reference::type Chris@102: polymorphic_get( Chris@102: boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) Chris@102: { Chris@102: #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT Chris@102: return polymorphic_relaxed_get(operand); Chris@102: #else Chris@102: return polymorphic_strict_get(operand); Chris@102: #endif Chris@102: } Chris@102: Chris@102: template Chris@102: inline Chris@102: typename add_reference::type Chris@102: polymorphic_get( Chris@102: const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand Chris@102: BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U) Chris@102: ) Chris@102: { Chris@102: #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT Chris@102: return polymorphic_relaxed_get(operand); Chris@102: #else Chris@102: return polymorphic_strict_get(operand); Chris@102: #endif Chris@102: } Chris@102: } // namespace boost Chris@102: Chris@102: #endif // BOOST_VARIANT_POLYMORPHIC_GET_HPP