File indexing completed on 2025-01-18 09:53:33
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_VARIANT_POLYMORPHIC_GET_HPP
0013 #define BOOST_VARIANT_POLYMORPHIC_GET_HPP
0014
0015 #include <exception>
0016
0017 #include <boost/config.hpp>
0018 #include <boost/core/addressof.hpp>
0019 #include <boost/detail/workaround.hpp>
0020 #include <boost/static_assert.hpp>
0021 #include <boost/throw_exception.hpp>
0022 #include <boost/variant/variant_fwd.hpp>
0023 #include <boost/variant/get.hpp>
0024
0025 #include <boost/type_traits/add_reference.hpp>
0026 #include <boost/type_traits/add_pointer.hpp>
0027 #include <boost/type_traits/is_base_of.hpp>
0028 #include <boost/type_traits/is_const.hpp>
0029
0030 namespace boost {
0031
0032
0033
0034
0035
0036
0037 class BOOST_SYMBOL_VISIBLE bad_polymorphic_get
0038 : public bad_get
0039 {
0040 public:
0041
0042 virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW
0043 {
0044 return "boost::bad_polymorphic_get: "
0045 "failed value get using boost::polymorphic_get";
0046 }
0047
0048 };
0049
0050
0051
0052
0053
0054
0055
0056
0057 namespace detail { namespace variant {
0058
0059
0060
0061
0062
0063
0064 template <class Types, class T>
0065 struct element_polymorphic_iterator_impl :
0066 boost::mpl::find_if<
0067 Types,
0068 boost::mpl::or_<
0069 variant_element_functor<boost::mpl::_1, T>,
0070 variant_element_functor<boost::mpl::_1, typename boost::remove_cv<T>::type >,
0071 boost::is_base_of<T, boost::mpl::_1>
0072 >
0073 >
0074 {};
0075
0076 template <class Variant, class T>
0077 struct holds_element_polymorphic :
0078 boost::mpl::not_<
0079 boost::is_same<
0080 typename boost::mpl::end<typename Variant::types>::type,
0081 typename element_polymorphic_iterator_impl<typename Variant::types, typename boost::remove_reference<T>::type >::type
0082 >
0083 >
0084 {};
0085
0086
0087
0088
0089
0090
0091
0092 template <typename Base>
0093 struct get_polymorphic_visitor
0094 {
0095 private:
0096 typedef get_polymorphic_visitor<Base> this_type;
0097 typedef typename add_pointer<Base>::type pointer;
0098 typedef typename add_reference<Base>::type reference;
0099
0100 pointer get(reference operand, boost::true_type) const BOOST_NOEXCEPT
0101 {
0102 return boost::addressof(operand);
0103 }
0104
0105 template <class T>
0106 pointer get(T&, boost::false_type) const BOOST_NOEXCEPT
0107 {
0108 return static_cast<pointer>(0);
0109 }
0110
0111 public:
0112 typedef pointer result_type;
0113
0114 template <typename U>
0115 pointer operator()(U& operand) const BOOST_NOEXCEPT
0116 {
0117 typedef typename boost::remove_reference<Base>::type base_t;
0118 typedef boost::integral_constant<
0119 bool,
0120 (
0121 boost::is_base_of<base_t, U>::value &&
0122 (boost::is_const<base_t>::value || !boost::is_const<U>::value)
0123 )
0124 || boost::is_same<base_t, U>::value
0125 || boost::is_same<typename boost::remove_cv<base_t>::type, U >::value
0126 > tag_t;
0127
0128 return this_type::get(operand, tag_t());
0129 }
0130 };
0131
0132 }}
0133
0134 #ifndef BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE
0135 # if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x0551))
0136 # define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t)
0137 # else
0138 # if defined(BOOST_NO_CXX11_NULLPTR)
0139 # define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t) \
0140 , t* = 0
0141 # else
0142 # define BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(t) \
0143 , t* = nullptr
0144 # endif
0145 # endif
0146 #endif
0147
0148
0149
0150
0151
0152 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0153 inline
0154 typename add_pointer<U>::type
0155 polymorphic_relaxed_get(
0156 boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
0157 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0158 ) BOOST_NOEXCEPT
0159 {
0160 typedef typename add_pointer<U>::type U_ptr;
0161 if (!operand) return static_cast<U_ptr>(0);
0162
0163 detail::variant::get_polymorphic_visitor<U> v;
0164 return operand->apply_visitor(v);
0165 }
0166
0167 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0168 inline
0169 typename add_pointer<const U>::type
0170 polymorphic_relaxed_get(
0171 const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
0172 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0173 ) BOOST_NOEXCEPT
0174 {
0175 typedef typename add_pointer<const U>::type U_ptr;
0176 if (!operand) return static_cast<U_ptr>(0);
0177
0178 detail::variant::get_polymorphic_visitor<const U> v;
0179 return operand->apply_visitor(v);
0180 }
0181
0182 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0183 inline
0184 typename add_reference<U>::type
0185 polymorphic_relaxed_get(
0186 boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
0187 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0188 )
0189 {
0190 typedef typename add_pointer<U>::type U_ptr;
0191 U_ptr result = polymorphic_relaxed_get<U>(&operand);
0192
0193 if (!result)
0194 boost::throw_exception(bad_polymorphic_get());
0195 return *result;
0196 }
0197
0198 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0199 inline
0200 typename add_reference<const U>::type
0201 polymorphic_relaxed_get(
0202 const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
0203 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0204 )
0205 {
0206 typedef typename add_pointer<const U>::type U_ptr;
0207 U_ptr result = polymorphic_relaxed_get<const U>(&operand);
0208
0209 if (!result)
0210 boost::throw_exception(bad_polymorphic_get());
0211 return *result;
0212 }
0213
0214
0215
0216
0217
0218 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0219 inline
0220 typename add_pointer<U>::type
0221 polymorphic_strict_get(
0222 boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
0223 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0224 ) BOOST_NOEXCEPT
0225 {
0226 BOOST_STATIC_ASSERT_MSG(
0227 (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
0228 "boost::variant does not contain specified type U, "
0229 "call to boost::polymorphic_get<U>(boost::variant<T...>*) will always return NULL"
0230 );
0231
0232 return polymorphic_relaxed_get<U>(operand);
0233 }
0234
0235 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0236 inline
0237 typename add_pointer<const U>::type
0238 polymorphic_strict_get(
0239 const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
0240 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0241 ) BOOST_NOEXCEPT
0242 {
0243 BOOST_STATIC_ASSERT_MSG(
0244 (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
0245 "boost::variant does not contain specified type U, "
0246 "call to boost::polymorphic_get<U>(const boost::variant<T...>*) will always return NULL"
0247 );
0248
0249 return polymorphic_relaxed_get<U>(operand);
0250 }
0251
0252 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0253 inline
0254 typename add_reference<U>::type
0255 polymorphic_strict_get(
0256 boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
0257 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0258 )
0259 {
0260 BOOST_STATIC_ASSERT_MSG(
0261 (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
0262 "boost::variant does not contain specified type U, "
0263 "call to boost::polymorphic_get<U>(boost::variant<T...>&) will always throw boost::bad_polymorphic_get exception"
0264 );
0265
0266 return polymorphic_relaxed_get<U>(operand);
0267 }
0268
0269 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0270 inline
0271 typename add_reference<const U>::type
0272 polymorphic_strict_get(
0273 const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
0274 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0275 )
0276 {
0277 BOOST_STATIC_ASSERT_MSG(
0278 (boost::detail::variant::holds_element_polymorphic<boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >, U >::value),
0279 "boost::variant does not contain specified type U, "
0280 "call to boost::polymorphic_get<U>(const boost::variant<T...>&) will always throw boost::bad_polymorphic_get exception"
0281 );
0282
0283 return polymorphic_relaxed_get<U>(operand);
0284 }
0285
0286
0287
0288
0289
0290 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0291 inline
0292 typename add_pointer<U>::type
0293 polymorphic_get(
0294 boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
0295 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0296 ) BOOST_NOEXCEPT
0297 {
0298 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
0299 return polymorphic_relaxed_get<U>(operand);
0300 #else
0301 return polymorphic_strict_get<U>(operand);
0302 #endif
0303
0304 }
0305
0306 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0307 inline
0308 typename add_pointer<const U>::type
0309 polymorphic_get(
0310 const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >* operand
0311 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0312 ) BOOST_NOEXCEPT
0313 {
0314 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
0315 return polymorphic_relaxed_get<U>(operand);
0316 #else
0317 return polymorphic_strict_get<U>(operand);
0318 #endif
0319 }
0320
0321 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0322 inline
0323 typename add_reference<U>::type
0324 polymorphic_get(
0325 boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
0326 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0327 )
0328 {
0329 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
0330 return polymorphic_relaxed_get<U>(operand);
0331 #else
0332 return polymorphic_strict_get<U>(operand);
0333 #endif
0334 }
0335
0336 template <typename U, BOOST_VARIANT_ENUM_PARAMS(typename T) >
0337 inline
0338 typename add_reference<const U>::type
0339 polymorphic_get(
0340 const boost::variant< BOOST_VARIANT_ENUM_PARAMS(T) >& operand
0341 BOOST_VARIANT_AUX_GET_EXPLICIT_TEMPLATE_TYPE(U)
0342 )
0343 {
0344 #ifdef BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
0345 return polymorphic_relaxed_get<U>(operand);
0346 #else
0347 return polymorphic_strict_get<U>(operand);
0348 #endif
0349 }
0350 }
0351
0352 #endif