libstdc++: Simplify C++20 implementation of std::variant
For C++20 the __detail::__variant::_Uninitialized primary template can be used for all types, because _Variant_union can have a non-trivially destructible union member in C++20, and the constrained user-provided destructor will ensure we don't destroy inactive objects. Since we always use the primary template for C++20, we don't need the _Uninitialized::_M_get accessors to abstract the difference between the primary template and the partial specialization. That allows us to simplify __get_n for C++20 too. Also improve the comments that explain the uses of _Uninitialized and when/why _Variant_union needs a user-provided destructor. libstdc++-v3/ChangeLog: * include/std/variant [C++20] (_Uninitialized): Always use the primary template. [C++20] (__get_n): Access the _M_storage member directly.
This commit is contained in:
parent
b25b101bc3
commit
0bb26524ae
1 changed files with 37 additions and 46 deletions
|
@ -54,10 +54,9 @@
|
|||
|
||||
// C++ < 20 || __cpp_concepts < 202002L || __cpp_constexpr < 201811L
|
||||
#if __cpp_lib_variant < 202106L
|
||||
# include <ext/aligned_buffer.h> // Use __aligned_membuf instead of union.
|
||||
# include <ext/aligned_buffer.h> // Use __aligned_membuf for storage.
|
||||
#endif
|
||||
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
@ -209,17 +208,18 @@ namespace __variant
|
|||
__as(const std::variant<_Types...>&& __v) noexcept
|
||||
{ return std::move(__v); }
|
||||
|
||||
// For C++17:
|
||||
// _Uninitialized<T> is guaranteed to be a trivially destructible type,
|
||||
// even if T is not.
|
||||
// For C++20:
|
||||
// _Uninitialized<T> is trivially destructible iff T is, so _Variant_union
|
||||
// needs a constrained non-trivial destructor.
|
||||
#if __cpp_lib_variant < 202106L
|
||||
template<typename _Type, bool = std::is_trivially_destructible_v<_Type>>
|
||||
struct _Uninitialized;
|
||||
#else
|
||||
template<typename _Type, bool /* unused */ = true>
|
||||
struct _Uninitialized;
|
||||
#endif
|
||||
|
||||
template<typename _Type>
|
||||
struct _Uninitialized<_Type, true>
|
||||
// The primary template is used for trivially destructible types in C++17,
|
||||
// and for all types in C++20.
|
||||
template<typename _Type, bool>
|
||||
struct _Uninitialized
|
||||
{
|
||||
template<typename... _Args>
|
||||
constexpr
|
||||
|
@ -227,6 +227,7 @@ namespace __variant
|
|||
: _M_storage(std::forward<_Args>(__args)...)
|
||||
{ }
|
||||
|
||||
#if __cpp_lib_variant < 202106L
|
||||
constexpr const _Type& _M_get() const & noexcept
|
||||
{ return _M_storage; }
|
||||
|
||||
|
@ -238,46 +239,18 @@ namespace __variant
|
|||
|
||||
constexpr _Type&& _M_get() && noexcept
|
||||
{ return std::move(_M_storage); }
|
||||
#endif
|
||||
|
||||
_Type _M_storage;
|
||||
};
|
||||
|
||||
#if __cpp_lib_variant < 202106L
|
||||
// This partial specialization is used for non-trivially destructible types
|
||||
// in C++17, so that _Uninitialized<T> is trivially destructible and can be
|
||||
// used as a union member in _Variadic_union.
|
||||
template<typename _Type>
|
||||
struct _Uninitialized<_Type, false>
|
||||
{
|
||||
#if __cpp_lib_variant >= 202106L
|
||||
template<typename... _Args>
|
||||
constexpr
|
||||
_Uninitialized(in_place_index_t<0>, _Args&&... __args)
|
||||
: _M_storage(std::forward<_Args>(__args)...)
|
||||
{ }
|
||||
|
||||
constexpr ~_Uninitialized() { }
|
||||
|
||||
_Uninitialized(const _Uninitialized&) = default;
|
||||
_Uninitialized(_Uninitialized&&) = default;
|
||||
_Uninitialized& operator=(const _Uninitialized&) = default;
|
||||
_Uninitialized& operator=(_Uninitialized&&) = default;
|
||||
|
||||
constexpr const _Type& _M_get() const & noexcept
|
||||
{ return _M_storage; }
|
||||
|
||||
constexpr _Type& _M_get() & noexcept
|
||||
{ return _M_storage; }
|
||||
|
||||
constexpr const _Type&& _M_get() const && noexcept
|
||||
{ return std::move(_M_storage); }
|
||||
|
||||
constexpr _Type&& _M_get() && noexcept
|
||||
{ return std::move(_M_storage); }
|
||||
|
||||
struct _Empty_byte { };
|
||||
|
||||
union {
|
||||
_Empty_byte _M_empty;
|
||||
_Type _M_storage;
|
||||
};
|
||||
#else
|
||||
template<typename... _Args>
|
||||
constexpr
|
||||
_Uninitialized(in_place_index_t<0>, _Args&&... __args)
|
||||
|
@ -299,7 +272,6 @@ namespace __variant
|
|||
{ return std::move(*_M_storage._M_ptr()); }
|
||||
|
||||
__gnu_cxx::__aligned_membuf<_Type> _M_storage;
|
||||
#endif
|
||||
};
|
||||
|
||||
template<size_t _Np, typename _Union>
|
||||
|
@ -316,6 +288,22 @@ namespace __variant
|
|||
return __variant::__get_n<_Np - 3>(
|
||||
std::forward<_Union>(__u)._M_rest._M_rest._M_rest);
|
||||
}
|
||||
#else
|
||||
template<size_t _Np, typename _Union>
|
||||
constexpr auto&&
|
||||
__get_n(_Union&& __u) noexcept
|
||||
{
|
||||
if constexpr (_Np == 0)
|
||||
return std::forward<_Union>(__u)._M_first._M_storage;
|
||||
else if constexpr (_Np == 1)
|
||||
return std::forward<_Union>(__u)._M_rest._M_first._M_storage;
|
||||
else if constexpr (_Np == 2)
|
||||
return std::forward<_Union>(__u)._M_rest._M_rest._M_first._M_storage;
|
||||
else
|
||||
return __variant::__get_n<_Np - 3>(
|
||||
std::forward<_Union>(__u)._M_rest._M_rest._M_rest);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Returns the typed storage for __v.
|
||||
template<size_t _Np, typename _Variant>
|
||||
|
@ -428,6 +416,9 @@ namespace __variant
|
|||
|
||||
~_Variadic_union() = default;
|
||||
|
||||
// If any alternative type is not trivially destructible then we need a
|
||||
// user-provided destructor that does nothing. The active alternative
|
||||
// will be destroyed by _Variant_storage::_M_reset() instead of here.
|
||||
constexpr ~_Variadic_union()
|
||||
requires (!__trivially_destructible)
|
||||
{ }
|
||||
|
@ -486,7 +477,7 @@ namespace __variant
|
|||
constexpr
|
||||
_Variant_storage(in_place_index_t<_Np>, _Args&&... __args)
|
||||
: _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...),
|
||||
_M_index{_Np}
|
||||
_M_index{_Np}
|
||||
{ }
|
||||
|
||||
constexpr void
|
||||
|
@ -532,7 +523,7 @@ namespace __variant
|
|||
constexpr
|
||||
_Variant_storage(in_place_index_t<_Np>, _Args&&... __args)
|
||||
: _M_u(in_place_index<_Np>, std::forward<_Args>(__args)...),
|
||||
_M_index{_Np}
|
||||
_M_index{_Np}
|
||||
{ }
|
||||
|
||||
constexpr void
|
||||
|
|
Loading…
Add table
Reference in a new issue