#include <bits/exception_defines.h>
#include <bits/functional_hash.h>
#include <bits/invoke.h>
-#include <ext/aligned_buffer.h>
#include <bits/parse_numbers.h>
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_iterator_base_funcs.h>
#include <bits/stl_construct.h>
#include <bits/utility.h> // in_place_index_t
-#if __cplusplus > 201703L
+#if __cplusplus == 201703L
+# include <ext/aligned_buffer.h>
+#else
# include <compare>
#endif
} // namespace __variant
} // namespace __detail
-#define __cpp_lib_variant 202102L
+#if __cplusplus >= 202002L && __cpp_concepts
+// P2231R1 constexpr needs constexpr unions and constrained destructors.
+# define __cpp_lib_variant 202106L
+#else
+# define __cpp_lib_variant 202102L
+#endif
template<typename... _Types> class tuple;
template<typename... _Types> class variant;
__do_visit(_Visitor&& __visitor, _Variants&&... __variants);
template <typename... _Types, typename _Tp>
+ _GLIBCXX20_CONSTEXPR
decltype(auto)
__variant_cast(_Tp&& __rhs)
{
__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.
template<typename _Type, bool = std::is_trivially_destructible_v<_Type>>
struct _Uninitialized;
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); }
+
+ union {
+ char _M_nope;
+ _Type _M_storage;
+ };
+#else
template<typename... _Args>
constexpr
_Uninitialized(in_place_index_t<0>, _Args&&... __args)
{ return std::move(*_M_storage._M_ptr()); }
__gnu_cxx::__aligned_membuf<_Type> _M_storage;
+#endif
};
template<size_t _Np, typename _Union>
constexpr _Variadic_union() : _M_rest() { }
template<typename... _Args>
- constexpr _Variadic_union(in_place_index_t<0>, _Args&&... __args)
+ constexpr
+ _Variadic_union(in_place_index_t<0>, _Args&&... __args)
: _M_first(in_place_index<0>, std::forward<_Args>(__args)...)
{ }
template<size_t _Np, typename... _Args>
- constexpr _Variadic_union(in_place_index_t<_Np>, _Args&&... __args)
+ constexpr
+ _Variadic_union(in_place_index_t<_Np>, _Args&&... __args)
: _M_rest(in_place_index<_Np-1>, std::forward<_Args>(__args)...)
{ }
+#if __cpp_lib_variant >= 202106L
+ _Variadic_union(const _Variadic_union&) = default;
+ _Variadic_union(_Variadic_union&&) = default;
+ _Variadic_union& operator=(const _Variadic_union&) = default;
+ _Variadic_union& operator=(_Variadic_union&&) = default;
+
+ ~_Variadic_union() = default;
+
+ constexpr ~_Variadic_union()
+ requires (!__has_trivial_destructor(_First))
+ || (!__has_trivial_destructor(_Variadic_union<_Rest...>))
+ { }
+#endif
+
_Uninitialized<_First> _M_first;
_Variadic_union<_Rest...> _M_rest;
};
template<typename... _Types>
struct _Variant_storage<false, _Types...>
{
+ template<typename _Tp>
+ static constexpr size_t __index_of
+ = __detail::__variant::__index_of_v<_Tp, _Types...>;
+
constexpr
_Variant_storage()
: _M_index(static_cast<__index_type>(variant_npos))
_M_index{_Np}
{ }
- void _M_reset()
+ constexpr void
+ _M_reset()
{
if (!_M_valid()) [[unlikely]]
return;
_M_index = static_cast<__index_type>(variant_npos);
}
+ _GLIBCXX20_CONSTEXPR
~_Variant_storage()
{ _M_reset(); }
template<typename... _Types>
struct _Variant_storage<true, _Types...>
{
+ template<typename _Tp>
+ static constexpr size_t __index_of
+ = __detail::__variant::__index_of_v<_Tp, _Types...>;
+
constexpr
_Variant_storage()
: _M_index(static_cast<__index_type>(variant_npos))
_M_index{_Np}
{ }
- void _M_reset() noexcept
+ constexpr void
+ _M_reset() noexcept
{ _M_index = static_cast<__index_type>(variant_npos); }
constexpr bool
_Variant_storage<_Traits<_Types...>::_S_trivial_dtor, _Types...>;
template<typename _Tp, typename _Up>
- void __variant_construct_single(_Tp&& __lhs, _Up&& __rhs_mem)
+ _GLIBCXX20_CONSTEXPR
+ void
+ __variant_construct_single(_Tp&& __lhs, _Up&& __rhs_mem)
{
- void* __storage = std::addressof(__lhs._M_u);
- using _Type = remove_reference_t<decltype(__rhs_mem)>;
+ using _Type = __remove_cvref_t<_Up>;
+
if constexpr (!is_same_v<_Type, __variant_cookie>)
- ::new (__storage)
- _Type(std::forward<decltype(__rhs_mem)>(__rhs_mem));
+ {
+ using _Lhs = remove_reference_t<_Tp>;
+ std::_Construct(std::__addressof(__lhs._M_u),
+ in_place_index<_Lhs::template __index_of<_Type>>,
+ std::forward<_Up>(__rhs_mem));
+ }
}
template<typename... _Types, typename _Tp, typename _Up>
- void __variant_construct(_Tp&& __lhs, _Up&& __rhs)
+ _GLIBCXX20_CONSTEXPR
+ void
+ __variant_construct(_Tp&& __lhs, _Up&& __rhs)
{
__lhs._M_index = __rhs._M_index;
__variant::__raw_visit([&__lhs](auto&& __rhs_mem) mutable
using _Base = _Variant_storage_alias<_Types...>;
using _Base::_Base;
+ _GLIBCXX20_CONSTEXPR
_Copy_ctor_base(const _Copy_ctor_base& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_copy_ctor)
{
using _Base = _Copy_ctor_alias<_Types...>;
using _Base::_Base;
+ _GLIBCXX20_CONSTEXPR
_Move_ctor_base(_Move_ctor_base&& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_move_ctor)
{
}
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs)
{
this->_M_reset();
}
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs)
{
this->_M_reset();
using _Base::_Base;
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
void _M_destructive_move(unsigned short __rhs_index, _Up&& __rhs)
{
this->_M_reset();
}
template<typename _Up>
+ _GLIBCXX20_CONSTEXPR
void _M_destructive_copy(unsigned short __rhs_index, const _Up& __rhs)
{
this->_M_reset();
using _Base = _Move_ctor_alias<_Types...>;
using _Base::_Base;
+ _GLIBCXX20_CONSTEXPR
_Copy_assign_base&
operator=(const _Copy_assign_base& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_copy_assign)
using _Base = _Copy_assign_alias<_Types...>;
using _Base::_Base;
+ _GLIBCXX20_CONSTEXPR
_Move_assign_base&
operator=(_Move_assign_base&& __rhs)
noexcept(_Traits<_Types...>::_S_nothrow_move_assign)
using _Base = _Move_assign_alias<_Types...>;
constexpr
- _Variant_base()
- noexcept(_Traits<_Types...>::_S_nothrow_default_ctor)
+ _Variant_base() noexcept(_Traits<_Types...>::_S_nothrow_default_ctor)
: _Variant_base(in_place_index<0>) { }
template<size_t _Np, typename... _Args>
}
template<size_t _Np, typename _Variant, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
inline void
__construct_by_index(_Variant& __v, _Args&&... __args)
{
- auto&& __storage = __detail::__variant::__get<_Np>(__v);
- ::new ((void*)std::addressof(__storage))
- remove_reference_t<decltype(__storage)>
- (std::forward<_Args>(__args)...);
+ std::_Construct(std::__addressof(__variant::__get<_Np>(__v)),
+ std::forward<_Args>(__args)...);
// Construction didn't throw, so can set the new index now:
__v._M_index = _Np;
}
visit(_Visitor&&, _Variants&&...);
template<typename... _Types>
+ _GLIBCXX20_CONSTEXPR
inline enable_if_t<(is_move_constructible_v<_Types> && ...)
&& (is_swappable_v<_Types> && ...)>
swap(variant<_Types...>& __lhs, variant<_Types...>& __rhs)
{
private:
template <typename... _UTypes, typename _Tp>
- friend decltype(auto) __variant_cast(_Tp&&);
+ friend _GLIBCXX20_CONSTEXPR decltype(auto)
+ __variant_cast(_Tp&&);
+
template<size_t _Np, typename _Variant, typename... _Args>
- friend void
+ friend _GLIBCXX20_CONSTEXPR void
__detail::__variant::__construct_by_index(_Variant& __v,
_Args&&... __args);
variant(variant&&) = default;
variant& operator=(const variant&) = default;
variant& operator=(variant&&) = default;
- ~variant() = default;
+ _GLIBCXX20_CONSTEXPR ~variant() = default;
template<typename _Tp,
typename = enable_if_t<sizeof...(_Types) != 0>,
{ }
template<typename _Tp>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<__exactly_once<__accepted_type<_Tp&&>>
&& is_constructible_v<__accepted_type<_Tp&&>, _Tp>
&& is_assignable_v<__accepted_type<_Tp&&>&, _Tp>,
}
template<typename _Tp, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<_Tp, _Args...> && __exactly_once<_Tp>,
_Tp&>
emplace(_Args&&... __args)
}
template<typename _Tp, typename _Up, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
&& __exactly_once<_Tp>,
_Tp&>
}
template<size_t _Np, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
_Args...>,
variant_alternative_t<_Np, variant>&>
}
template<size_t _Np, typename _Up, typename... _Args>
+ _GLIBCXX20_CONSTEXPR
enable_if_t<is_constructible_v<variant_alternative_t<_Np, variant>,
initializer_list<_Up>&, _Args...>,
variant_alternative_t<_Np, variant>&>
return size_t(__index_type(this->_M_index + 1)) - 1;
}
+ _GLIBCXX20_CONSTEXPR
void
swap(variant& __rhs)
noexcept((__is_nothrow_swappable<_Types>::value && ...)
--- /dev/null
+// { dg-options "-std=gnu++20" }
+// { dg-do compile { target c++20 } }
+
+#include <variant>
+
+// P2231R1 Missing constexpr in std::optional and std::variant
+
+#ifndef __cpp_lib_variant
+#error "Feature test macro for variant is missing in <variant>"
+#elif __cpp_lib_variant < 202106L
+# error "Feature test macro for variant has wrong value for C++20 in <variant>"
+#endif
+
+#include <testsuite_hooks.h>
+
+
+constexpr bool
+test_assign()
+{
+ std::variant<int, double> v1(1);
+ v1 = 2.5;
+ VERIFY( std::get<double>(v1) == 2.5 );
+
+ v1 = 99;
+ VERIFY( std::get<int>(v1) == 99 );
+ v1 = 999;
+ VERIFY( std::get<int>(v1) == 999 );
+
+ struct S // non-trivial special members
+ {
+ constexpr S(int i) : i(i) { }
+ constexpr ~S() { }
+ constexpr S(const S& s) : i(s.i) { }
+
+ int i;
+ };
+
+ std::variant<int, S> v;
+ v = S(123);
+ VERIFY( std::get<1>(v).i == 123 );
+
+ const S s(456);
+ v = s;
+ VERIFY( std::get<1>(v).i == 456 );
+
+ v = 789;
+ VERIFY( std::get<0>(v) == 789 );
+
+ return true;
+}
+
+static_assert( test_assign() );
+
+constexpr bool
+test_emplace()
+{
+ struct S // non-trivial special members
+ {
+ constexpr S(std::initializer_list<int> l) : i(l.begin()[0]) { }
+ constexpr S(std::initializer_list<int> l, int n) : i(l.begin()[n]) { }
+ constexpr ~S() { }
+ constexpr S(const S& s) : i(s.i) { }
+
+ int i;
+ };
+
+ std::variant<int, double, S> v(1);
+
+ // template<class T, class... Args> constexpr T& emplace(Args&&... args);
+ v.emplace<double>(2.0);
+ VERIFY( std::get<1>(v) == 2.0 );
+ v.emplace<double>(2.5);
+ VERIFY( std::get<1>(v) == 2.5 );
+ v.emplace<int>(2.5);
+ VERIFY( std::get<0>(v) == 2 );
+
+ // template<class T, class U, class... Args>
+ // constexpr T& emplace(initializer_list<U>, Args&&... args);
+ v.emplace<S>({3, 2, 1});
+ VERIFY( std::get<2>(v).i == 3 );
+ v.emplace<S>({3, 2, 1}, 1);
+ VERIFY( std::get<2>(v).i == 2 );
+
+ // template<size_t I, class... Args>
+ // constexpr variant_alternative_t<I, ...>& emplace(Args&&... args);
+ v.emplace<1>(3.0);
+ VERIFY( std::get<1>(v) == 3.0 );
+ v.emplace<1>(0.5);
+ VERIFY( std::get<1>(v) == 0.5 );
+ v.emplace<0>(1.5);
+ VERIFY( std::get<0>(v) == 1 );
+
+ // template<size_t I, class U, class... Args>
+ // constexpr variant_alternative_t<I, ...>&
+ // emplace(initializer_list<U>, Args&&... args);
+ v.emplace<2>({7, 8, 9});
+ VERIFY( std::get<2>(v).i == 7 );
+ v.emplace<2>({13, 12, 11}, 1);
+ VERIFY( std::get<2>(v).i == 12 );
+
+ return true;
+}
+
+static_assert( test_emplace() );
+
+constexpr bool
+test_swap()
+{
+ std::variant<int, double> v1(1), v2(2.5);
+ v1.swap(v2);
+ VERIFY( std::get<double>(v1) == 2.5 );
+ VERIFY( std::get<int>(v2) == 1 );
+
+ swap(v1, v2);
+ VERIFY( std::get<int>(v1) == 1 );
+ VERIFY( std::get<double>(v2) == 2.5 );
+
+ struct S
+ {
+ constexpr S(int i) : i(i) { }
+ constexpr S(S&& s) : i(s.i) { }
+ constexpr S& operator=(S&& s) { i = s.i; s.i = -1; return *this; }
+
+ int i;
+ };
+
+ std::variant<int, S> v3(3), v4(S(4));
+ v3.swap(v4);
+ VERIFY( std::get<S>(v3).i == 4 );
+ VERIFY( std::get<int>(v4) == 3 );
+ v3.swap(v4);
+ VERIFY( std::get<int>(v3) == 3 );
+ VERIFY( std::get<S>(v4).i == 4 );
+
+ return true;
+}
+
+static_assert( test_swap() );