From 724a40baec3ded142c631b66521502840d8d183f Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 25 Jun 2014 15:29:29 +0100 Subject: [PATCH] support implicit type convertions two pass value type index calculation * exact match std::is_same<> * implicit conversion is_convertible<> --- variant.hpp | 58 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/variant.hpp b/variant.hpp index 8ded0ce..5627bd9 100644 --- a/variant.hpp +++ b/variant.hpp @@ -40,19 +40,43 @@ namespace mapbox { namespace util { namespace detail { static constexpr std::size_t invalid_value = std::size_t(-1); template -struct type_traits; +struct direct_type; template -struct type_traits +struct direct_type { - static constexpr std::size_t id = std::is_same::value - ? sizeof...(Types) : type_traits::id; + static constexpr std::size_t index = std::is_same::value + ? sizeof...(Types) : direct_type::index; }; template -struct type_traits +struct direct_type { - static constexpr std::size_t id = invalid_value; + static constexpr std::size_t index = invalid_value; +}; + +template +struct convertible_type; + +template +struct convertible_type +{ + static constexpr std::size_t index = std::is_convertible::value + ? sizeof...(Types) : convertible_type::index; +}; + +template +struct convertible_type +{ + static constexpr std::size_t index = invalid_value; +}; + +template +struct value_traits +{ + static constexpr std::size_t direct_index = direct_type::index; + static constexpr std::size_t index = + (direct_index == invalid_value) ? convertible_type::index : direct_index; }; template @@ -61,7 +85,7 @@ struct is_valid_type; template struct is_valid_type { - static constexpr bool value = std::is_same::value + static constexpr bool value = std::is_convertible::value || is_valid_type::value; }; @@ -488,17 +512,21 @@ class variant template ::value>::type> VARIANT_INLINE explicit variant(T const& val) noexcept - : type_index(detail::type_traits::id) + : type_index(detail::value_traits::index) { - new (&data) T(val); + constexpr std::size_t index = sizeof...(Types) - detail::value_traits::index - 1; + using target_type = typename detail::select_type::type; + new (&data) target_type(val); } template ::value>::type> VARIANT_INLINE variant(T && val) noexcept - : type_index(detail::type_traits::id) + : type_index(detail::value_traits::index) { - new (&data) T(std::forward(val)); // nothrow + constexpr std::size_t index = sizeof...(Types) - detail::value_traits::index - 1; + using target_type = typename detail::select_type::type; + new (&data) target_type(std::forward(val)); // nothrow } VARIANT_INLINE variant(variant const& old) @@ -548,7 +576,7 @@ class variant template VARIANT_INLINE bool is() const { - return (type_index == detail::type_traits::id); + return (type_index == detail::direct_type::index); } VARIANT_INLINE bool valid() const @@ -561,13 +589,13 @@ class variant { helper_type::destroy(type_index, &data); new (&data) T(std::forward(args)...); - type_index = detail::type_traits::id; + type_index = detail::direct_type::index; } template VARIANT_INLINE T& get() { - if (type_index == detail::type_traits::id) + if (type_index == detail::direct_type::index) { return *reinterpret_cast(&data); } @@ -580,7 +608,7 @@ class variant template VARIANT_INLINE T const& get() const { - if (type_index == detail::type_traits::id) + if (type_index == detail::direct_type::index) { return *reinterpret_cast(&data); }