libstdc++: Implement std::pair/tuple/misc enhancements from P2321R2
This implements the non-<ranges> changes from P2321R2, which primarily consist of additional converting constructors, assignment operator and swap overloads for std::pair and std::tuple. libstdc++-v3/ChangeLog: * include/bits/stl_bvector.h (_Bit_reference::operator=): Define const overload for C++23 as per P2321R2. * include/bits/stl_pair.h (pair::swap): Likewise. (pair::pair): Define additional converting constructors for C++23 as per P2321R2. (pair::operator=): Define const overloads for C++23 as per P2321R2. (swap): Define overload taking const pair& for C++23 as per P2321R2. (basic_common_reference): Define partial specialization for pair for C++23 as per P2321R2. (common_type): Likewise. * include/bits/uses_allocator_args.h (uses_allocator_construction_args): Define additional pair overloads for C++23 as per P2321R2. * include/std/tuple (_Tuple_impl::_Tuple_impl): Define additional converting constructors for C++23 as per P2321R2. (_Tuple_impl::_M_assign): Define const overloads for C++23 as per P2321R2. (_Tuple_impl::_M_swap): Likewise. (tuple::__constructible): Define as a convenient renaming of _TCC<true>::__constructible. (tuple::__convertible): As above but for _TCC<true>::__convertible. (tuple::tuple): Define additional converting constructors for C++23 as per P2321R2. (tuple::operator=): Define const overloads for C++23 as per P2321R2. (tuple::swap): Likewise. (basic_common_reference): Define partial specialization for tuple for C++23 as per P2321R2. (common_type): Likewise. * testsuite/20_util/pair/p2321r2.cc: New test. * testsuite/20_util/tuple/p2321r2.cc: New test. * testsuite/23_containers/vector/bool/element_access/1.cc: New test.
This commit is contained in:
parent
02f6b405f0
commit
72886fcc62
7 changed files with 1479 additions and 5 deletions
|
@ -106,6 +106,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
|
|||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
constexpr const _Bit_reference&
|
||||
operator=(bool __x) const noexcept
|
||||
{
|
||||
if (__x)
|
||||
*_M_p |= _M_mask;
|
||||
else
|
||||
*_M_p &= ~_M_mask;
|
||||
return *this;
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
_Bit_reference&
|
||||
operator=(const _Bit_reference& __x) _GLIBCXX_NOEXCEPT
|
||||
|
|
|
@ -212,6 +212,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
swap(second, __p.second);
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
constexpr void
|
||||
swap(const pair& __p) const
|
||||
noexcept(__and_v<__is_nothrow_swappable<const _T1>,
|
||||
__is_nothrow_swappable<const _T2>>)
|
||||
{
|
||||
using std::swap;
|
||||
swap(first, __p.first);
|
||||
swap(second, __p.second);
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
private:
|
||||
template<typename... _Args1, size_t... _Indexes1,
|
||||
typename... _Args2, size_t... _Indexes2>
|
||||
|
@ -283,7 +295,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
: first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y))
|
||||
{ }
|
||||
|
||||
/// Converting constructor from a `pair<U1, U2>` lvalue
|
||||
/// Converting constructor from a const `pair<U1, U2>` lvalue
|
||||
template<typename _U1, typename _U2>
|
||||
requires (_S_constructible<const _U1&, const _U2&>())
|
||||
constexpr explicit(!_S_convertible<const _U1&, const _U2&>())
|
||||
|
@ -292,7 +304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
: first(__p.first), second(__p.second)
|
||||
{ }
|
||||
|
||||
/// Converting constructor from a `pair<U1, U2>` rvalue
|
||||
/// Converting constructor from a non-const `pair<U1, U2>` rvalue
|
||||
template<typename _U1, typename _U2>
|
||||
requires (_S_constructible<_U1, _U2>())
|
||||
constexpr explicit(!_S_convertible<_U1, _U2>())
|
||||
|
@ -302,6 +314,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
second(std::forward<_U2>(__p.second))
|
||||
{ }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
/// Converting constructor from a non-const `pair<U1, U2>` lvalue
|
||||
template<typename _U1, typename _U2>
|
||||
requires (_S_constructible<_U1&, _U2&>())
|
||||
constexpr explicit(!_S_convertible<_U1&, _U2&>())
|
||||
pair(pair<_U1, _U2>& __p)
|
||||
noexcept(_S_nothrow_constructible<_U1&, _U2&>())
|
||||
: first(__p.first), second(__p.second)
|
||||
{ }
|
||||
|
||||
/// Converting constructor from a const `pair<U1, U2>` rvalue
|
||||
template<typename _U1, typename _U2>
|
||||
requires (_S_constructible<const _U1, const _U2>())
|
||||
constexpr explicit(!_S_convertible<const _U1, const _U2>())
|
||||
pair(const pair<_U1, _U2>&& __p)
|
||||
noexcept(_S_nothrow_constructible<const _U1, const _U2>())
|
||||
: first(std::forward<const _U1>(__p.first)),
|
||||
second(std::forward<const _U2>(__p.second))
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
private:
|
||||
/// @cond undocumented
|
||||
template<typename _U1, typename _U2>
|
||||
|
@ -349,7 +382,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return *this;
|
||||
}
|
||||
|
||||
/// Converting assignment from a `pair<U1, U2>` lvalue
|
||||
/// Converting assignment from a const `pair<U1, U2>` lvalue
|
||||
template<typename _U1, typename _U2>
|
||||
constexpr pair&
|
||||
operator=(const pair<_U1, _U2>& __p)
|
||||
|
@ -361,7 +394,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return *this;
|
||||
}
|
||||
|
||||
/// Converting assignment from a `pair<U1, U2>` rvalue
|
||||
/// Converting assignment from a non-const `pair<U1, U2>` rvalue
|
||||
template<typename _U1, typename _U2>
|
||||
constexpr pair&
|
||||
operator=(pair<_U1, _U2>&& __p)
|
||||
|
@ -372,7 +405,55 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
second = std::forward<_U2>(__p.second);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
/// Copy assignment operator (const)
|
||||
constexpr const pair&
|
||||
operator=(const pair& __p) const
|
||||
requires is_copy_assignable_v<const first_type>
|
||||
&& is_copy_assignable_v<const second_type>
|
||||
{
|
||||
first = __p.first;
|
||||
second = __p.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Move assignment operator (const)
|
||||
constexpr const pair&
|
||||
operator=(pair&& __p) const
|
||||
requires is_assignable_v<const first_type&, first_type>
|
||||
&& is_assignable_v<const second_type&, second_type>
|
||||
{
|
||||
first = std::forward<first_type>(__p.first);
|
||||
second = std::forward<second_type>(__p.second);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Converting assignment from a const `pair<U1, U2>` lvalue
|
||||
template<typename _U1, typename _U2>
|
||||
constexpr const pair&
|
||||
operator=(const pair<_U1, _U2>& __p) const
|
||||
requires is_assignable_v<const first_type&, const _U1&>
|
||||
&& is_assignable_v<const second_type&, const _U2&>
|
||||
{
|
||||
first = __p.first;
|
||||
second = __p.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Converting assignment from a non-const `pair<U1, U2>` rvalue
|
||||
template<typename _U1, typename _U2>
|
||||
constexpr const pair&
|
||||
operator=(pair<_U1, _U2>&& __p) const
|
||||
requires is_assignable_v<const first_type&, _U1>
|
||||
&& is_assignable_v<const second_type&, _U2>
|
||||
{
|
||||
first = std::forward<_U1>(__p.first);
|
||||
second = std::forward<_U2>(__p.second);
|
||||
return *this;
|
||||
}
|
||||
#endif // C++23
|
||||
#else // !__cpp_lib_concepts
|
||||
// C++11/14/17 implementation using enable_if, partially constexpr.
|
||||
|
||||
/** The default constructor creates @c first and @c second using their
|
||||
|
@ -710,6 +791,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
noexcept(noexcept(__x.swap(__y)))
|
||||
{ __x.swap(__y); }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _T1, typename _T2>
|
||||
requires is_swappable_v<const _T1> && is_swappable_v<const _T2>
|
||||
constexpr void
|
||||
swap(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y)
|
||||
noexcept(noexcept(__x.swap(__y)))
|
||||
{ __x.swap(__y); }
|
||||
#endif // C++23
|
||||
|
||||
#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
|
||||
template<typename _T1, typename _T2>
|
||||
typename enable_if<!__and_<__is_swappable<_T1>,
|
||||
|
@ -918,6 +1008,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
get(const pair<_Up, _Tp>&& __p) noexcept
|
||||
{ return std::move(__p.second); }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _T1, typename _T2, typename _U1, typename _U2,
|
||||
template<typename> class _TQual, template<typename> class _UQual>
|
||||
requires requires { typename pair<common_reference_t<_TQual<_T1>, _UQual<_U1>>,
|
||||
common_reference_t<_TQual<_T2>, _UQual<_U2>>>; }
|
||||
struct basic_common_reference<pair<_T1, _T2>, pair<_U1, _U2>, _TQual, _UQual>
|
||||
{
|
||||
using type = pair<common_reference_t<_TQual<_T1>, _UQual<_U1>>,
|
||||
common_reference_t<_TQual<_T2>, _UQual<_U2>>>;
|
||||
};
|
||||
|
||||
template<typename _T1, typename _T2, typename _U1, typename _U2>
|
||||
requires requires { typename pair<common_type_t<_T1, _U1>, common_type_t<_T2, _U2>>; }
|
||||
struct common_type<pair<_T1, _T2>, pair<_U1, _U2>>
|
||||
{ using type = pair<common_type_t<_T1, _U1>, common_type_t<_T2, _U2>>; };
|
||||
#endif // C++23
|
||||
|
||||
#endif // C++14
|
||||
/// @}
|
||||
#endif // C++11
|
||||
|
|
|
@ -107,6 +107,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
constexpr auto
|
||||
uses_allocator_construction_args(const _Alloc&, pair<_Up, _Vp>&&) noexcept;
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
|
||||
constexpr auto
|
||||
uses_allocator_construction_args(const _Alloc&,
|
||||
pair<_Up, _Vp>&) noexcept;
|
||||
|
||||
template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
|
||||
constexpr auto
|
||||
uses_allocator_construction_args(const _Alloc&, const pair<_Up, _Vp>&&) noexcept;
|
||||
#endif // C++23
|
||||
|
||||
template<_Std_pair _Tp, typename _Alloc, typename _Tuple1, typename _Tuple2>
|
||||
constexpr auto
|
||||
uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t,
|
||||
|
@ -181,6 +192,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
std::move(__pr).second));
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
|
||||
constexpr auto
|
||||
uses_allocator_construction_args(const _Alloc& __a,
|
||||
pair<_Up, _Vp>& __pr) noexcept
|
||||
{
|
||||
using _Tp1 = typename _Tp::first_type;
|
||||
using _Tp2 = typename _Tp::second_type;
|
||||
|
||||
return std::make_tuple(piecewise_construct,
|
||||
std::uses_allocator_construction_args<_Tp1>(__a, __pr.first),
|
||||
std::uses_allocator_construction_args<_Tp2>(__a, __pr.second));
|
||||
}
|
||||
|
||||
template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp>
|
||||
constexpr auto
|
||||
uses_allocator_construction_args(const _Alloc& __a,
|
||||
const pair<_Up, _Vp>&& __pr) noexcept
|
||||
{
|
||||
using _Tp1 = typename _Tp::first_type;
|
||||
using _Tp2 = typename _Tp::second_type;
|
||||
|
||||
return std::make_tuple(piecewise_construct,
|
||||
std::uses_allocator_construction_args<_Tp1>(__a,
|
||||
std::move(__pr).first),
|
||||
std::uses_allocator_construction_args<_Tp2>(__a,
|
||||
std::move(__pr).second));
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
template<typename _Tp, typename _Alloc, typename... _Args>
|
||||
constexpr _Tp
|
||||
make_obj_using_allocator(const _Alloc& __a, _Args&&... __args)
|
||||
|
|
|
@ -316,6 +316,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)))
|
||||
{ }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename... _UElements>
|
||||
constexpr
|
||||
_Tuple_impl(_Tuple_impl<_Idx, _UElements...>& __in)
|
||||
: _Inherited(_Tuple_impl<_Idx, _UElements...>::_M_tail(__in)),
|
||||
_Base(_Tuple_impl<_Idx, _UElements...>::_M_head(__in))
|
||||
{ }
|
||||
|
||||
template<typename _UHead, typename... _UTails>
|
||||
constexpr
|
||||
_Tuple_impl(const _Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
|
||||
: _Inherited(std::move
|
||||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))),
|
||||
_Base(std::forward<const _UHead>
|
||||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)))
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
template<typename _Alloc>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a)
|
||||
|
@ -379,6 +397,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)))
|
||||
{ }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _Alloc, typename _UHead, typename... _UTails>
|
||||
constexpr
|
||||
_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
|
||||
_Tuple_impl<_Idx, _UHead, _UTails...>& __in)
|
||||
: _Inherited(__tag, __a,
|
||||
_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in)),
|
||||
_Base(__use_alloc<_Head, _Alloc, _UHead&>(__a),
|
||||
_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))
|
||||
{ }
|
||||
|
||||
template<typename _Alloc, typename _UHead, typename... _UTails>
|
||||
constexpr
|
||||
_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
|
||||
const _Tuple_impl<_Idx, _UHead, _UTails...>&& __in)
|
||||
: _Inherited(__tag, __a, std::move
|
||||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))),
|
||||
_Base(__use_alloc<_Head, _Alloc, const _UHead>(__a),
|
||||
std::forward<const _UHead>
|
||||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)))
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
template<typename... _UElements>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
|
@ -400,6 +441,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
std::move(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in)));
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename... _UElements>
|
||||
constexpr void
|
||||
_M_assign(const _Tuple_impl<_Idx, _UElements...>& __in) const
|
||||
{
|
||||
_M_head(*this) = _Tuple_impl<_Idx, _UElements...>::_M_head(__in);
|
||||
_M_tail(*this)._M_assign(
|
||||
_Tuple_impl<_Idx, _UElements...>::_M_tail(__in));
|
||||
}
|
||||
|
||||
template<typename _UHead, typename... _UTails>
|
||||
constexpr void
|
||||
_M_assign(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in) const
|
||||
{
|
||||
_M_head(*this) = std::forward<_UHead>
|
||||
(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in));
|
||||
_M_tail(*this)._M_assign(
|
||||
std::move(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in)));
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
protected:
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
|
@ -409,6 +471,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
swap(_M_head(*this), _M_head(__in));
|
||||
_Inherited::_M_swap(_M_tail(__in));
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
constexpr void
|
||||
_M_swap(const _Tuple_impl& __in) const
|
||||
{
|
||||
using std::swap;
|
||||
swap(_M_head(*this), _M_head(__in));
|
||||
_Inherited::_M_swap(_M_tail(__in));
|
||||
}
|
||||
#endif // C++23
|
||||
};
|
||||
|
||||
// Basis case of inheritance recursion.
|
||||
|
@ -469,6 +541,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
: _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)))
|
||||
{ }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _UHead>
|
||||
constexpr
|
||||
_Tuple_impl(_Tuple_impl<_Idx, _UHead>& __in)
|
||||
: _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in))
|
||||
{ }
|
||||
|
||||
template<typename _UHead>
|
||||
constexpr
|
||||
_Tuple_impl(const _Tuple_impl<_Idx, _UHead>&& __in)
|
||||
: _Base(std::forward<const _UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)))
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
template<typename _Alloc>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a)
|
||||
|
@ -521,6 +607,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)))
|
||||
{ }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _Alloc, typename _UHead>
|
||||
constexpr
|
||||
_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
|
||||
_Tuple_impl<_Idx, _UHead>& __in)
|
||||
: _Base(__use_alloc<_Head, _Alloc, _UHead&>(__a),
|
||||
_Tuple_impl<_Idx, _UHead>::_M_head(__in))
|
||||
{ }
|
||||
|
||||
template<typename _Alloc, typename _UHead>
|
||||
constexpr
|
||||
_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a,
|
||||
const _Tuple_impl<_Idx, _UHead>&& __in)
|
||||
: _Base(__use_alloc<_Head, _Alloc, const _UHead>(__a),
|
||||
std::forward<const _UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)))
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
template<typename _UHead>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
|
@ -538,6 +642,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
= std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in));
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _UHead>
|
||||
constexpr void
|
||||
_M_assign(const _Tuple_impl<_Idx, _UHead>& __in) const
|
||||
{
|
||||
_M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in);
|
||||
}
|
||||
|
||||
template<typename _UHead>
|
||||
constexpr void
|
||||
_M_assign(_Tuple_impl<_Idx, _UHead>&& __in) const
|
||||
{
|
||||
_M_head(*this)
|
||||
= std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in));
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
protected:
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
|
@ -546,6 +667,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
using std::swap;
|
||||
swap(_M_head(*this), _M_head(__in));
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
constexpr void
|
||||
_M_swap(const _Tuple_impl& __in) const
|
||||
{
|
||||
using std::swap;
|
||||
swap(_M_head(*this), _M_head(__in));
|
||||
}
|
||||
#endif // C++23
|
||||
};
|
||||
|
||||
// Concept utility functions, reused in conditionally-explicit
|
||||
|
@ -712,6 +842,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
static constexpr bool __use_other_ctor()
|
||||
{ return _UseOtherCtor<_Tuple>::value; }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename... _Args>
|
||||
static constexpr bool __constructible
|
||||
= _TCC<true>::template __constructible<_Args...>::value;
|
||||
|
||||
template<typename... _Args>
|
||||
static constexpr bool __convertible
|
||||
= _TCC<true>::template __convertible<_Args...>::value;
|
||||
#endif // C++23
|
||||
|
||||
public:
|
||||
template<typename _Dummy = void,
|
||||
_ImplicitDefaultCtor<is_void<_Dummy>::value> = true>
|
||||
|
@ -799,6 +939,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
noexcept(__nothrow_constructible<_UElements...>())
|
||||
: _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename... _UElements>
|
||||
requires (sizeof...(_Elements) == sizeof...(_UElements))
|
||||
&& (!__use_other_ctor<tuple<_UElements...>&>())
|
||||
&& __constructible<_UElements&...>
|
||||
explicit(!__convertible<_UElements&...>)
|
||||
constexpr
|
||||
tuple(tuple<_UElements...>& __in)
|
||||
noexcept(__nothrow_constructible<_UElements&...>())
|
||||
: _Inherited(static_cast<_Tuple_impl<0, _UElements...>&>(__in))
|
||||
{ }
|
||||
|
||||
template<typename... _UElements>
|
||||
requires (sizeof...(_Elements) == sizeof...(_UElements))
|
||||
&& (!__use_other_ctor<const tuple<_UElements...>&&>())
|
||||
&& __constructible<const _UElements...>
|
||||
explicit(!__convertible<const _UElements...>)
|
||||
constexpr
|
||||
tuple(const tuple<_UElements...>&& __in)
|
||||
noexcept(__nothrow_constructible<const _UElements...>())
|
||||
: _Inherited(static_cast<const _Tuple_impl<0, _UElements...>&&>(__in)) { }
|
||||
#endif // C++23
|
||||
|
||||
// Allocator-extended constructors.
|
||||
|
||||
template<typename _Alloc,
|
||||
|
@ -897,6 +1060,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
static_cast<_Tuple_impl<0, _UElements...>&&>(__in))
|
||||
{ }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _Alloc, typename... _UElements>
|
||||
requires (sizeof...(_Elements) == sizeof...(_UElements))
|
||||
&& (!__use_other_ctor<tuple<_UElements...>&>())
|
||||
&& __constructible<_UElements&...>
|
||||
explicit(!__convertible<_UElements&...>)
|
||||
constexpr
|
||||
tuple(allocator_arg_t __tag, const _Alloc& __a,
|
||||
tuple<_UElements...>& __in)
|
||||
: _Inherited(__tag, __a,
|
||||
static_cast<_Tuple_impl<0, _UElements...>&>(__in))
|
||||
{ }
|
||||
|
||||
template<typename _Alloc, typename... _UElements>
|
||||
requires (sizeof...(_Elements) == sizeof...(_UElements))
|
||||
&& (!__use_other_ctor<const tuple<_UElements...>>())
|
||||
&& __constructible<const _UElements...>
|
||||
explicit(!__convertible<const _UElements...>)
|
||||
constexpr
|
||||
tuple(allocator_arg_t __tag, const _Alloc& __a,
|
||||
const tuple<_UElements...>&& __in)
|
||||
: _Inherited(__tag, __a,
|
||||
static_cast<const _Tuple_impl<0, _UElements...>&&>(__in))
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
// tuple assignment
|
||||
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
|
@ -941,12 +1130,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
constexpr const tuple&
|
||||
operator=(const tuple& __in) const
|
||||
requires (is_copy_assignable_v<const _Elements> && ...)
|
||||
{
|
||||
this->_M_assign(__in);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr const tuple&
|
||||
operator=(tuple&& __in) const
|
||||
requires (is_assignable_v<const _Elements&, _Elements> && ...)
|
||||
{
|
||||
this->_M_assign(std::move(__in));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... _UElements>
|
||||
constexpr const tuple&
|
||||
operator=(const tuple<_UElements...>& __in) const
|
||||
requires (sizeof...(_Elements) == sizeof...(_UElements))
|
||||
&& (is_assignable_v<const _Elements&, const _UElements&> && ...)
|
||||
{
|
||||
this->_M_assign(__in);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename... _UElements>
|
||||
constexpr const tuple&
|
||||
operator=(tuple<_UElements...>&& __in) const
|
||||
requires (sizeof...(_Elements) == sizeof...(_UElements))
|
||||
&& (is_assignable_v<const _Elements&, _UElements> && ...)
|
||||
{
|
||||
this->_M_assign(std::move(__in));
|
||||
return *this;
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
// tuple swap
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
swap(tuple& __in)
|
||||
noexcept(__and_<__is_nothrow_swappable<_Elements>...>::value)
|
||||
{ _Inherited::_M_swap(__in); }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
constexpr void
|
||||
swap(const tuple& __in) const
|
||||
noexcept(__and_v<__is_nothrow_swappable<const _Elements>...>)
|
||||
{ _Inherited::_M_swap(__in); }
|
||||
#endif // C++23
|
||||
};
|
||||
|
||||
#if __cpp_deduction_guides >= 201606
|
||||
|
@ -969,6 +1203,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
public:
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void swap(tuple&) noexcept { /* no-op */ }
|
||||
#if __cplusplus > 202002L
|
||||
constexpr void swap(const tuple&) const noexcept { /* no-op */ }
|
||||
#endif
|
||||
// We need the default since we're going to define no-op
|
||||
// allocator constructors.
|
||||
tuple() = default;
|
||||
|
@ -1048,6 +1285,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
static constexpr bool __is_alloc_arg()
|
||||
{ return is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value; }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _U1, typename _U2>
|
||||
static constexpr bool __constructible
|
||||
= _TCC<true>::template __constructible<_U1, _U2>::value;
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
static constexpr bool __convertible
|
||||
= _TCC<true>::template __convertible<_U1, _U2>::value;
|
||||
#endif // C++23
|
||||
|
||||
public:
|
||||
template<bool _Dummy = true,
|
||||
_ImplicitDefaultCtor<_Dummy, _T1, _T2> = true>
|
||||
|
@ -1123,6 +1370,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
noexcept(__nothrow_constructible<_U1, _U2>())
|
||||
: _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _U1, typename _U2>
|
||||
requires __constructible<_U1&, _U2&>
|
||||
explicit(!__convertible<_U1&, _U2&>)
|
||||
constexpr
|
||||
tuple(tuple<_U1, _U2>& __in)
|
||||
noexcept(__nothrow_constructible<_U1&, _U2&>())
|
||||
: _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&>(__in)) { }
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
requires __constructible<const _U1, const _U2>
|
||||
explicit(!__convertible<const _U1, const _U2>)
|
||||
constexpr
|
||||
tuple(const tuple<_U1, _U2>&& __in)
|
||||
noexcept(__nothrow_constructible<const _U1, const _U2>())
|
||||
: _Inherited(static_cast<const _Tuple_impl<0, _U1, _U2>&&>(__in)) { }
|
||||
#endif // C++23
|
||||
|
||||
template<typename _U1, typename _U2,
|
||||
_ImplicitCtor<true, const _U1&, const _U2&> = true>
|
||||
constexpr
|
||||
|
@ -1153,6 +1418,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
: _Inherited(std::forward<_U1>(__in.first),
|
||||
std::forward<_U2>(__in.second)) { }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _U1, typename _U2>
|
||||
requires __constructible<_U1&, _U2&>
|
||||
explicit(!__convertible<_U1&, _U2&>)
|
||||
constexpr
|
||||
tuple(pair<_U1, _U2>& __in)
|
||||
noexcept(__nothrow_constructible<_U1&, _U2&>())
|
||||
: _Inherited(__in.first, __in.second) { }
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
requires __constructible<const _U1, const _U2>
|
||||
explicit(!__convertible<const _U1, const _U2>)
|
||||
constexpr
|
||||
tuple(const pair<_U1, _U2>&& __in)
|
||||
noexcept(__nothrow_constructible<const _U1, const _U2>())
|
||||
: _Inherited(std::forward<const _U1>(__in.first),
|
||||
std::forward<const _U2>(__in.second)) { }
|
||||
#endif // C++23
|
||||
|
||||
// Allocator-extended constructors.
|
||||
|
||||
template<typename _Alloc,
|
||||
|
@ -1236,6 +1520,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
: _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in))
|
||||
{ }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _Alloc, typename _U1, typename _U2>
|
||||
requires __constructible<_U1&, _U2&>
|
||||
explicit(!__convertible<_U1&, _U2&>)
|
||||
constexpr
|
||||
tuple(allocator_arg_t __tag, const _Alloc& __a,
|
||||
tuple<_U1, _U2>& __in)
|
||||
: _Inherited(__tag, __a,
|
||||
static_cast<_Tuple_impl<0, _U1, _U2>&>(__in))
|
||||
{ }
|
||||
|
||||
template<typename _Alloc, typename _U1, typename _U2>
|
||||
requires __constructible<const _U1, const _U2>
|
||||
explicit(!__convertible<const _U1, const _U2>)
|
||||
constexpr
|
||||
tuple(allocator_arg_t __tag, const _Alloc& __a,
|
||||
const tuple<_U1, _U2>&& __in)
|
||||
: _Inherited(__tag, __a,
|
||||
static_cast<const _Tuple_impl<0, _U1, _U2>&&>(__in))
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
template<typename _Alloc, typename _U1, typename _U2,
|
||||
_ImplicitCtor<true, const _U1&, const _U2&> = true>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
|
@ -1266,6 +1572,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
: _Inherited(__tag, __a, std::forward<_U1>(__in.first),
|
||||
std::forward<_U2>(__in.second)) { }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _Alloc, typename _U1, typename _U2>
|
||||
requires __constructible<_U1&, _U2&>
|
||||
explicit(!__convertible<_U1&, _U2&>)
|
||||
constexpr
|
||||
tuple(allocator_arg_t __tag, const _Alloc& __a,
|
||||
pair<_U1, _U2>& __in)
|
||||
: _Inherited(__tag, __a, __in.first, __in.second) { }
|
||||
|
||||
template<typename _Alloc, typename _U1, typename _U2>
|
||||
requires __constructible<const _U1, const _U2>
|
||||
explicit(!__convertible<const _U1, const _U2>)
|
||||
constexpr
|
||||
tuple(allocator_arg_t __tag, const _Alloc& __a, const pair<_U1, _U2>&& __in)
|
||||
: _Inherited(__tag, __a, std::forward<const _U1>(__in.first),
|
||||
std::forward<const _U2>(__in.second)) { }
|
||||
#endif // C++23
|
||||
|
||||
// Tuple assignment.
|
||||
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
|
@ -1310,6 +1634,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
constexpr const tuple&
|
||||
operator=(const tuple& __in) const
|
||||
requires is_copy_assignable_v<const _T1> && is_copy_assignable_v<const _T2>
|
||||
{
|
||||
this->_M_assign(__in);
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr const tuple&
|
||||
operator=(tuple&& __in) const
|
||||
requires is_assignable_v<const _T1&, _T1> && is_assignable_v<const _T2, _T2>
|
||||
{
|
||||
this->_M_assign(std::move(__in));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
constexpr const tuple&
|
||||
operator=(const tuple<_U1, _U2>& __in) const
|
||||
requires is_assignable_v<const _T1&, const _U1&>
|
||||
&& is_assignable_v<const _T2&, const _U2&>
|
||||
{
|
||||
this->_M_assign(__in);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
constexpr const tuple&
|
||||
operator=(tuple<_U1, _U2>&& __in) const
|
||||
requires is_assignable_v<const _T1&, _U1>
|
||||
&& is_assignable_v<const _T2&, _U2>
|
||||
{
|
||||
this->_M_assign(std::move(__in));
|
||||
return *this;
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
__enable_if_t<__assignable<const _U1&, const _U2&>(), tuple&>
|
||||
|
@ -1332,12 +1694,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return *this;
|
||||
}
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename _U1, typename _U2>
|
||||
constexpr const tuple&
|
||||
operator=(const pair<_U1, _U2>& __in) const
|
||||
requires is_assignable_v<const _T1&, const _U1&>
|
||||
&& is_assignable_v<const _T2&, const _U2&>
|
||||
{
|
||||
this->_M_head(*this) = __in.first;
|
||||
this->_M_tail(*this)._M_head(*this) = __in.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename _U1, typename _U2>
|
||||
constexpr const tuple&
|
||||
operator=(pair<_U1, _U2>&& __in) const
|
||||
requires is_assignable_v<const _T1&, _U1>
|
||||
&& is_assignable_v<const _T2&, _U2>
|
||||
{
|
||||
this->_M_head(*this) = std::forward<_U1>(__in.first);
|
||||
this->_M_tail(*this)._M_head(*this) = std::forward<_U2>(__in.second);
|
||||
return *this;
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
swap(tuple& __in)
|
||||
noexcept(__and_<__is_nothrow_swappable<_T1>,
|
||||
__is_nothrow_swappable<_T2>>::value)
|
||||
{ _Inherited::_M_swap(__in); }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
constexpr void
|
||||
swap(const tuple& __in) const
|
||||
noexcept(__and_v<__is_nothrow_swappable<const _T1>,
|
||||
__is_nothrow_swappable<const _T2>>)
|
||||
{ _Inherited::_M_swap(__in); }
|
||||
#endif // C++23
|
||||
};
|
||||
|
||||
|
||||
|
@ -1765,6 +2159,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
noexcept(noexcept(__x.swap(__y)))
|
||||
{ __x.swap(__y); }
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename... _Elements>
|
||||
requires (is_swappable_v<const _Elements> && ...)
|
||||
constexpr void
|
||||
swap(const tuple<_Elements...>& __x, const tuple<_Elements...>& __y)
|
||||
noexcept(noexcept(__x.swap(__y)))
|
||||
{ __x.swap(__y); }
|
||||
#endif // C++23
|
||||
|
||||
#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11
|
||||
template<typename... _Elements>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
|
@ -1889,6 +2292,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
#endif // C++17
|
||||
|
||||
#if __cplusplus > 202002L
|
||||
template<typename... _TTypes, typename... _UTypes,
|
||||
template<typename> class TQual, template<typename> class UQual>
|
||||
requires requires { typename tuple<common_reference_t<TQual<_TTypes>, UQual<_UTypes>>...>; }
|
||||
struct basic_common_reference<tuple<_TTypes...>, tuple<_UTypes...>, TQual, UQual>
|
||||
{ using type = tuple<common_reference_t<TQual<_TTypes>, UQual<_UTypes>>...>; };
|
||||
|
||||
template<typename... _TTypes, typename... _UTypes>
|
||||
requires requires { typename tuple<common_type_t<_TTypes, _UTypes>...>; }
|
||||
struct common_type<tuple<_TTypes...>, tuple<_UTypes...>>
|
||||
{ using type = tuple<common_type_t<_TTypes, _UTypes>...>; };
|
||||
#endif // C++23
|
||||
|
||||
/// @}
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
|
|
208
libstdc++-v3/testsuite/20_util/pair/p2321r2.cc
Normal file
208
libstdc++-v3/testsuite/20_util/pair/p2321r2.cc
Normal file
|
@ -0,0 +1,208 @@
|
|||
// Verify P2321R2 "zip" enhancements to std::pair.
|
||||
// { dg-options "-std=gnu++23" }
|
||||
// { dg-do run { target c++23 } }
|
||||
|
||||
#include <utility>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using std::pair;
|
||||
|
||||
struct A { };
|
||||
|
||||
constexpr bool
|
||||
test01()
|
||||
{
|
||||
struct B { bool v; constexpr B(A&) : v(true) { } };
|
||||
|
||||
// template<class U1, class U2>
|
||||
// constexpr explicit(false) pair(pair<U1, U2>&);
|
||||
|
||||
pair<A, int> p2a0;
|
||||
pair<B, int> p2b0 = p2a0;
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
pair<int, A> p2a1;
|
||||
pair<int, B> p2b1 = p2a1;
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test02()
|
||||
{
|
||||
struct B { bool v; explicit constexpr B(A&) : v(true) { } };
|
||||
|
||||
// template<class U1, class U2>
|
||||
// constexpr explicit(true) pair(pair<U1, U2>&);
|
||||
|
||||
static_assert(!std::is_convertible_v<pair<A, int>&, pair<B, int>>);
|
||||
static_assert(!std::is_convertible_v<pair<int, A>&, pair<int, B>>);
|
||||
|
||||
pair<A, int> p2a0;
|
||||
pair<B, int> p2b0(p2a0);
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
pair<int, A> p2a1;
|
||||
pair<int, B> p2b1(p2a1);
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test03()
|
||||
{
|
||||
struct B { bool v; constexpr B(const A&&) : v(true) { } };
|
||||
|
||||
// template<class U1, class U2>
|
||||
// constexpr explicit(false) pair(const pair<U1, U2>&&);
|
||||
|
||||
const pair<A, int> p2a0;
|
||||
pair<B, int> p2b0 = std::move(p2a0);
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
const pair<int, A> p2a1;
|
||||
pair<int, B> p2b1 = std::move(p2a1);
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test04()
|
||||
{
|
||||
struct B { bool v; explicit constexpr B(const A&&) : v(true) { } };
|
||||
|
||||
// template<class U1, class U2>
|
||||
// constexpr explicit(true) pair(const pair<U1, U2>&&);
|
||||
|
||||
static_assert(!std::is_convertible_v<const pair<A, int>&&, pair<B, int>>);
|
||||
static_assert(!std::is_convertible_v<const pair<int, A>&&, pair<int, B>>);
|
||||
|
||||
const pair<A, int> p2a0;
|
||||
pair<B, int> p2b0(std::move(p2a0));
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
const pair<int, A> p2a1;
|
||||
pair<int, B> p2b1(std::move(p2a1));
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test05()
|
||||
{
|
||||
struct B
|
||||
{
|
||||
mutable bool v;
|
||||
constexpr const B& operator=(const A&) const { v = true; return *this; }
|
||||
};
|
||||
|
||||
// template<class U1, class U2>
|
||||
// constexpr const pair& operator=(const pair<U1, U2>&) const;
|
||||
|
||||
const pair<A, A> p2a;
|
||||
const pair<B, B> p2b;
|
||||
p2b = p2a;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test06()
|
||||
{
|
||||
struct B
|
||||
{
|
||||
mutable bool v;
|
||||
constexpr const B& operator=(A&&) const { v = true; return *this; }
|
||||
};
|
||||
|
||||
// template<class U1, class U2>
|
||||
// constexpr const pair& operator=(pair<U1, U2>&&) const;
|
||||
|
||||
pair<A, A> p2a;
|
||||
const pair<B, B> p2b;
|
||||
p2b = std::move(p2a);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test07()
|
||||
{
|
||||
struct B
|
||||
{
|
||||
mutable bool v;
|
||||
constexpr const B& operator=(const B&) const { v = true; return *this; }
|
||||
};
|
||||
|
||||
// constexpr const pair& operator=(const pair&) const;
|
||||
|
||||
const pair<B, B> t2a;
|
||||
const pair<B, B> t2b;
|
||||
t2b = t2a;
|
||||
VERIFY( std::get<0>(t2b).v );
|
||||
VERIFY( std::get<1>(t2b).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test08()
|
||||
{
|
||||
struct B
|
||||
{
|
||||
mutable bool v;
|
||||
constexpr const B& operator=(B&&) const { v = true; return *this; }
|
||||
};
|
||||
|
||||
// constexpr const pair& operator=(pair&&) const;
|
||||
|
||||
pair<B, B> t2a;
|
||||
const pair<B, B> t2b;
|
||||
t2b = std::move(t2a);
|
||||
VERIFY( std::get<0>(t2b).v );
|
||||
VERIFY( std::get<1>(t2b).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct S
|
||||
{
|
||||
mutable int v = 0;
|
||||
friend constexpr void swap(S&& x, S&& y) = delete;
|
||||
friend constexpr void swap(const S& x, const S& y) { ++x.v; ++y.v; }
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
test09()
|
||||
{
|
||||
const pair<S, S> t2, u2;
|
||||
std::swap(t2, u2);
|
||||
VERIFY( std::get<0>(t2).v == 1 );
|
||||
VERIFY( std::get<0>(u2).v == 1 );
|
||||
VERIFY( std::get<1>(t2).v == 1 );
|
||||
VERIFY( std::get<1>(u2).v == 1 );
|
||||
|
||||
static_assert(!std::is_swappable_v<const pair<A, int>&>);
|
||||
static_assert(!std::is_swappable_v<const pair<int, A>&>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
static_assert(test01());
|
||||
static_assert(test02());
|
||||
static_assert(test03());
|
||||
static_assert(test04());
|
||||
// FIXME: G++ doesn't support reading mutable members during constexpr (PR c++/92505).
|
||||
test05();
|
||||
test06();
|
||||
test07();
|
||||
test08();
|
||||
test09();
|
||||
}
|
664
libstdc++-v3/testsuite/20_util/tuple/p2321r2.cc
Normal file
664
libstdc++-v3/testsuite/20_util/tuple/p2321r2.cc
Normal file
|
@ -0,0 +1,664 @@
|
|||
// Verify P2321R2 "zip" enhancements to std::tuple.
|
||||
// { dg-options "-std=gnu++23" }
|
||||
// { dg-do run { target c++23 } }
|
||||
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using std::tuple;
|
||||
using std::pair;
|
||||
using std::allocator;
|
||||
using std::allocator_arg_t;
|
||||
using std::allocator_arg;
|
||||
|
||||
namespace alloc {
|
||||
struct B01;
|
||||
struct B02;
|
||||
struct B03;
|
||||
struct B04;
|
||||
}
|
||||
|
||||
template<> struct std::uses_allocator<alloc::B01, allocator<int>> : std::true_type { };
|
||||
template<> struct std::uses_allocator<alloc::B02, allocator<int>> : std::true_type { };
|
||||
template<> struct std::uses_allocator<alloc::B03, allocator<int>> : std::true_type { };
|
||||
template<> struct std::uses_allocator<alloc::B04, allocator<int>> : std::true_type { };
|
||||
|
||||
struct A { };
|
||||
|
||||
constexpr bool
|
||||
test01()
|
||||
{
|
||||
struct B { bool v; constexpr B(A&) : v(true) { } };
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr explicit(false) tuple(tuple<UTypes...>&);
|
||||
|
||||
tuple<A> t1a;
|
||||
tuple<B> t1b = t1a;
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
tuple<A, int> t2a0;
|
||||
tuple<B, int> t2b0 = t2a0;
|
||||
VERIFY( std::get<0>(t2b0).v );
|
||||
|
||||
tuple<int, A> t2a1;
|
||||
tuple<int, B> t2b1 = t2a1;
|
||||
VERIFY( std::get<1>(t2b1).v );
|
||||
|
||||
tuple<A, int, int> t3a0;
|
||||
tuple<B, int, int> t3b0 = t3a0;
|
||||
VERIFY( std::get<0>(t3b0).v );
|
||||
|
||||
tuple<int, A, int> t3a1;
|
||||
tuple<int, B, int> t3b1 = t3a1;
|
||||
VERIFY( std::get<1>(t3b1).v );
|
||||
|
||||
tuple<int, int, A> t3a2;
|
||||
tuple<int, int, B> t3b2 = t3a2;
|
||||
VERIFY( std::get<2>(t3b2).v );
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr explicit(false) tuple(pair<UTypes...>&);
|
||||
|
||||
pair<A, int> p2a0;
|
||||
tuple<B, int> p2b0 = p2a0;
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
pair<int, A> p2a1;
|
||||
tuple<int, B> p2b1 = p2a1;
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace alloc
|
||||
{
|
||||
struct B01
|
||||
{
|
||||
bool v;
|
||||
B01(A&);
|
||||
constexpr B01(allocator_arg_t, allocator<int>, A&) : v(true) { }
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
test01()
|
||||
{
|
||||
using B = B01;
|
||||
|
||||
// template<class Alloc, class... UTypes>
|
||||
// constexpr explicit(false)
|
||||
// tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&);
|
||||
|
||||
tuple<A> t1a;
|
||||
tuple<B> t1b = {allocator_arg, allocator<int>{}, t1a};
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
tuple<A, int> t2a0;
|
||||
tuple<B, int> t2b0 = {allocator_arg, allocator<int>{}, t2a0};
|
||||
VERIFY( std::get<0>(t2b0).v );
|
||||
|
||||
tuple<int, A> t2a1;
|
||||
tuple<int, B> t2b1 = {allocator_arg, allocator<int>{}, t2a1};
|
||||
VERIFY( std::get<1>(t2b1).v );
|
||||
|
||||
tuple<A, int, int> t3a0;
|
||||
tuple<B, int, int> t3b0 = {allocator_arg, allocator<int>{}, t3a0};
|
||||
VERIFY( std::get<0>(t3b0).v );
|
||||
|
||||
tuple<int, A, int> t3a1;
|
||||
tuple<int, B, int> t3b1 = {allocator_arg, allocator<int>{}, t3a1};
|
||||
VERIFY( std::get<1>(t3b1).v );
|
||||
|
||||
tuple<int, int, A> t3a2;
|
||||
tuple<int, int, B> t3b2 = {allocator_arg, allocator<int>{}, t3a2};
|
||||
VERIFY( std::get<2>(t3b2).v );
|
||||
|
||||
// template<class Alloc, class U1, class U2>
|
||||
// constexpr explicit(false)
|
||||
// tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&);
|
||||
|
||||
pair<A, int> p2a0;
|
||||
tuple<B, int> p2b0 = {allocator_arg, allocator<int>{}, p2a0};
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
pair<int, A> p2a1;
|
||||
tuple<int, B> p2b1 = {allocator_arg, allocator<int>{}, p2a1};
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test02()
|
||||
{
|
||||
struct B { bool v; explicit constexpr B(A&) : v(true) { } };
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr explicit(true) tuple(tuple<UTypes...>&);
|
||||
|
||||
static_assert(!std::is_convertible_v<tuple<A>&, tuple<B>>);
|
||||
|
||||
tuple<A> t1a;
|
||||
tuple<B> t1b(t1a);
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
static_assert(!std::is_convertible_v<tuple<A, int>&, tuple<B, int>>);
|
||||
static_assert(!std::is_convertible_v<tuple<int, A>&, tuple<int, B>>);
|
||||
|
||||
tuple<A, int> t2a0;
|
||||
tuple<B, int> t2b0(t2a0);
|
||||
VERIFY( std::get<0>(t2b0).v );
|
||||
|
||||
tuple<int, A> t2a1;
|
||||
tuple<int, B> t2b1(t2a1);
|
||||
VERIFY( std::get<1>(t2b1).v );
|
||||
|
||||
static_assert(!std::is_convertible_v<tuple<A, int, int>&, tuple<B, int, int>>);
|
||||
static_assert(!std::is_convertible_v<tuple<int, A, int>&, tuple<int, B, int>>);
|
||||
static_assert(!std::is_convertible_v<tuple<int, int, A>&, tuple<int, int, B>>);
|
||||
|
||||
tuple<A, int, int> t3a0;
|
||||
tuple<B, int, int> t3b0(t3a0);
|
||||
VERIFY( std::get<0>(t3b0).v );
|
||||
|
||||
tuple<int, A, int> t3a1;
|
||||
tuple<int, B, int> t3b1(t3a1);
|
||||
VERIFY( std::get<1>(t3b1).v );
|
||||
|
||||
tuple<int, int, A> t3a2;
|
||||
tuple<int, int, B> t3b2(t3a2);
|
||||
VERIFY( std::get<2>(t3b2).v );
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr explicit(true) tuple(pair<UTypes...>&);
|
||||
|
||||
static_assert(!std::is_convertible_v<pair<A, int>&, tuple<B, int>>);
|
||||
static_assert(!std::is_convertible_v<pair<int, A>&, tuple<int, B>>);
|
||||
|
||||
pair<A, int> p2a0;
|
||||
tuple<B, int> p2b0(p2a0);
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
pair<int, A> p2a1;
|
||||
tuple<int, B> p2b1(p2a1);
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace alloc
|
||||
{
|
||||
struct B02
|
||||
{
|
||||
bool v;
|
||||
explicit B02(A&);
|
||||
explicit constexpr B02(allocator_arg_t, allocator<int>, A&) : v(true) { }
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
test02()
|
||||
{
|
||||
using B = B02;
|
||||
|
||||
// template<class Alloc, class... UTypes>
|
||||
// constexpr explicit(true)
|
||||
// tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&);
|
||||
|
||||
tuple<A> t1a;
|
||||
tuple<B> t1b(allocator_arg, allocator<int>{}, t1a);
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
tuple<A, int> t2a0;
|
||||
tuple<B, int> t2b0(allocator_arg, allocator<int>{}, t2a0);
|
||||
VERIFY( std::get<0>(t2b0).v );
|
||||
|
||||
tuple<int, A> t2a1;
|
||||
tuple<int, B> t2b1(allocator_arg, allocator<int>{}, t2a1);
|
||||
VERIFY( std::get<1>(t2b1).v );
|
||||
|
||||
tuple<A, int, int> t3a0;
|
||||
tuple<B, int, int> t3b0(allocator_arg, allocator<int>{}, t3a0);
|
||||
VERIFY( std::get<0>(t3b0).v );
|
||||
|
||||
tuple<int, A, int> t3a1;
|
||||
tuple<int, B, int> t3b1(allocator_arg, allocator<int>{}, t3a1);
|
||||
VERIFY( std::get<1>(t3b1).v );
|
||||
|
||||
tuple<int, int, A> t3a2;
|
||||
tuple<int, int, B> t3b2(allocator_arg, allocator<int>{}, t3a2);
|
||||
VERIFY( std::get<2>(t3b2).v );
|
||||
|
||||
// template<class Alloc, class U1, class U2>
|
||||
// constexpr explicit(true)
|
||||
// tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&);
|
||||
|
||||
pair<A, int> p2a0;
|
||||
tuple<B, int> p2b0(allocator_arg, allocator<int>{}, p2a0);
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
pair<int, A> p2a1;
|
||||
tuple<int, B> p2b1(allocator_arg, allocator<int>{}, p2a1);
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace alloc
|
||||
|
||||
constexpr bool
|
||||
test03()
|
||||
{
|
||||
struct B { bool v; constexpr B(const A&&) : v(true) { } };
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr explicit(false) tuple(const tuple<UTypes...>&&);
|
||||
|
||||
const tuple<A> t1a;
|
||||
tuple<B> t1b = std::move(t1a);
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
const tuple<A, int> t2a0;
|
||||
tuple<B, int> t2b0 = std::move(t2a0);
|
||||
VERIFY( std::get<0>(t2b0).v );
|
||||
|
||||
const tuple<int, A> t2a1;
|
||||
tuple<int, B> t2b1 = std::move(t2a1);
|
||||
VERIFY( std::get<1>(t2b1).v );
|
||||
|
||||
const tuple<A, int, int> t3a0;
|
||||
tuple<B, int, int> t3b0 = std::move(t3a0);
|
||||
VERIFY( std::get<0>(t3b0).v );
|
||||
|
||||
const tuple<int, A, int> t3a1;
|
||||
tuple<int, B, int> t3b1 = std::move(t3a1);
|
||||
VERIFY( std::get<1>(t3b1).v );
|
||||
|
||||
const tuple<int, int, A> t3a2;
|
||||
tuple<int, int, B> t3b2 = std::move(t3a2);
|
||||
VERIFY( std::get<2>(t3b2).v );
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr explicit(false) tuple(const pair<UTypes...>&&);
|
||||
|
||||
const pair<A, int> p2a0;
|
||||
tuple<B, int> p2b0 = std::move(p2a0);
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
const pair<int, A> p2a1;
|
||||
tuple<int, B> p2b1 = std::move(p2a1);
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace alloc
|
||||
{
|
||||
struct B03
|
||||
{
|
||||
bool v;
|
||||
B03(const A&&);
|
||||
constexpr B03(allocator_arg_t, allocator<int>, const A&&) : v(true) { }
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
test03()
|
||||
{
|
||||
using B = B03;
|
||||
|
||||
// template<class Alloc, class... UTypes>
|
||||
// constexpr explicit(false)
|
||||
// tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&);
|
||||
|
||||
const tuple<A> t1a;
|
||||
tuple<B> t1b = {allocator_arg, allocator<int>{}, std::move(t1a)};
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
const tuple<A, int> t2a0;
|
||||
tuple<B, int> t2b0 = {allocator_arg, allocator<int>{}, std::move(t2a0)};
|
||||
VERIFY( std::get<0>(t2b0).v );
|
||||
|
||||
const tuple<int, A> t2a1;
|
||||
tuple<int, B> t2b1 = {allocator_arg, allocator<int>{}, std::move(t2a1)};
|
||||
VERIFY( std::get<1>(t2b1).v );
|
||||
|
||||
const tuple<A, int, int> t3a0;
|
||||
tuple<B, int, int> t3b0 = {allocator_arg, allocator<int>{}, std::move(t3a0)};
|
||||
VERIFY( std::get<0>(t3b0).v );
|
||||
|
||||
const tuple<int, A, int> t3a1;
|
||||
tuple<int, B, int> t3b1 = {allocator_arg, allocator<int>{}, std::move(t3a1)};
|
||||
VERIFY( std::get<1>(t3b1).v );
|
||||
|
||||
const tuple<int, int, A> t3a2;
|
||||
tuple<int, int, B> t3b2 = {allocator_arg, allocator<int>{}, std::move(t3a2)};
|
||||
VERIFY( std::get<2>(t3b2).v );
|
||||
|
||||
// template<class Alloc, class U1, class U2>
|
||||
// constexpr explicit(false)
|
||||
// tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&);
|
||||
|
||||
const pair<A, int> p2a0;
|
||||
tuple<B, int> p2b0 = {allocator_arg, allocator<int>{}, std::move(p2a0)};
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
const pair<int, A> p2a1;
|
||||
tuple<int, B> p2b1 = {allocator_arg, allocator<int>{}, std::move(p2a1)};
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
test04()
|
||||
{
|
||||
struct B { bool v; explicit constexpr B(const A&&) : v(true) { } };
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr explicit(true) tuple(const tuple<UTypes...>&&);
|
||||
|
||||
static_assert(!std::is_convertible_v<tuple<A>&, tuple<B>>);
|
||||
|
||||
const tuple<A> t1a;
|
||||
tuple<B> t1b(std::move(t1a));
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
static_assert(!std::is_convertible_v<tuple<A, int>&, tuple<B, int>>);
|
||||
static_assert(!std::is_convertible_v<tuple<int, A>&, tuple<int, B>>);
|
||||
|
||||
const tuple<A, int> t2a0;
|
||||
tuple<B, int> t2b0(std::move(t2a0));
|
||||
VERIFY( std::get<0>(t2b0).v );
|
||||
|
||||
const tuple<int, A> t2a1;
|
||||
tuple<int, B> t2b1(std::move(t2a1));
|
||||
VERIFY( std::get<1>(t2b1).v );
|
||||
|
||||
static_assert(!std::is_convertible_v<tuple<A, int, int>&, tuple<B, int, int>>);
|
||||
static_assert(!std::is_convertible_v<tuple<int, A, int>&, tuple<int, B, int>>);
|
||||
static_assert(!std::is_convertible_v<tuple<int, int, A>&, tuple<int, int, B>>);
|
||||
|
||||
const tuple<A, int, int> t3a0;
|
||||
tuple<B, int, int> t3b0(std::move(t3a0));
|
||||
VERIFY( std::get<0>(t3b0).v );
|
||||
|
||||
const tuple<int, A, int> t3a1;
|
||||
tuple<int, B, int> t3b1(std::move(t3a1));
|
||||
VERIFY( std::get<1>(t3b1).v );
|
||||
|
||||
const tuple<int, int, A> t3a2;
|
||||
tuple<int, int, B> t3b2(std::move(t3a2));
|
||||
VERIFY( std::get<2>(t3b2).v );
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr explicit(true) tuple(const pair<UTypes...>&&);
|
||||
|
||||
static_assert(!std::is_convertible_v<pair<A, int>&, tuple<B, int>>);
|
||||
static_assert(!std::is_convertible_v<pair<int, A>&, tuple<int, B>>);
|
||||
|
||||
const pair<A, int> p2a0;
|
||||
tuple<B, int> p2b0(std::move(p2a0));
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
const pair<int, A> p2a1;
|
||||
tuple<int, B> p2b1(std::move(p2a1));
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace alloc
|
||||
{
|
||||
struct B04
|
||||
{
|
||||
bool v;
|
||||
explicit B04(const A&&);
|
||||
explicit constexpr B04(allocator_arg_t, allocator<int>, const A&&) : v(true) { }
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
test04()
|
||||
{
|
||||
using B = B04;
|
||||
|
||||
// template<class Alloc, class... UTypes>
|
||||
// constexpr explicit(true)
|
||||
// tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&);
|
||||
|
||||
const tuple<A> t1a;
|
||||
tuple<B> t1b(allocator_arg, allocator<int>{}, std::move(t1a));
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
const tuple<A, int> t2a0;
|
||||
tuple<B, int> t2b0(allocator_arg, allocator<int>{}, std::move(t2a0));
|
||||
VERIFY( std::get<0>(t2b0).v );
|
||||
|
||||
const tuple<int, A> t2a1;
|
||||
tuple<int, B> t2b1(allocator_arg, allocator<int>{}, std::move(t2a1));
|
||||
VERIFY( std::get<1>(t2b1).v );
|
||||
|
||||
const tuple<A, int, int> t3a0;
|
||||
tuple<B, int, int> t3b0(allocator_arg, allocator<int>{}, std::move(t3a0));
|
||||
VERIFY( std::get<0>(t3b0).v );
|
||||
|
||||
const tuple<int, A, int> t3a1;
|
||||
tuple<int, B, int> t3b1(allocator_arg, allocator<int>{}, std::move(t3a1));
|
||||
VERIFY( std::get<1>(t3b1).v );
|
||||
|
||||
const tuple<int, int, A> t3a2;
|
||||
tuple<int, int, B> t3b2(allocator_arg, allocator<int>{}, std::move(t3a2));
|
||||
VERIFY( std::get<2>(t3b2).v );
|
||||
|
||||
// template<class Alloc, class U1, class U2>
|
||||
// constexpr explicit(true)
|
||||
// tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&);
|
||||
|
||||
tuple<B, int> p2b0(allocator_arg, allocator<int>{}, std::move(t2a0));
|
||||
VERIFY( std::get<0>(p2b0).v );
|
||||
|
||||
tuple<int, B> p2b1(allocator_arg, allocator<int>{}, std::move(t2a1));
|
||||
VERIFY( std::get<1>(p2b1).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
test05()
|
||||
{
|
||||
struct B
|
||||
{
|
||||
mutable bool v;
|
||||
constexpr const B& operator=(const A&) const { v = true; return *this; }
|
||||
};
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr const tuple& operator=(const tuple<UTypes...>&) const;
|
||||
|
||||
const tuple<A> t1a;
|
||||
const tuple<B> t1b;
|
||||
t1b = t1a;
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
const tuple<A, A> t2a;
|
||||
const tuple<B, B> t2b;
|
||||
t2b = t2a;
|
||||
VERIFY( std::get<0>(t2b).v );
|
||||
VERIFY( std::get<1>(t2b).v );
|
||||
|
||||
const tuple<A, A, A> t3a;
|
||||
const tuple<B, B, B> t3b;
|
||||
t3b = t3a;
|
||||
VERIFY( std::get<0>(t3b).v );
|
||||
VERIFY( std::get<1>(t3b).v );
|
||||
VERIFY( std::get<2>(t3b).v );
|
||||
|
||||
// template<class U1, class U2>
|
||||
// constexpr const tuple& operator=(const pair<U1, U2>&) const;
|
||||
|
||||
const pair<A, A> p2a;
|
||||
const tuple<B, B> p2b;
|
||||
p2b = p2a;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test06()
|
||||
{
|
||||
struct B
|
||||
{
|
||||
mutable bool v;
|
||||
constexpr const B& operator=(A&&) const { v = true; return *this; }
|
||||
};
|
||||
|
||||
// template<class... UTypes>
|
||||
// constexpr const tuple& operator=(tuple<UTypes...>&&) const;
|
||||
|
||||
tuple<A> t1a;
|
||||
const tuple<B> t1b;
|
||||
t1b = std::move(t1a);
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
tuple<A, A> t2a;
|
||||
const tuple<B, B> t2b;
|
||||
t2b = std::move(t2a);
|
||||
VERIFY( std::get<0>(t2b).v );
|
||||
VERIFY( std::get<1>(t2b).v );
|
||||
|
||||
tuple<A, A, A> t3a;
|
||||
const tuple<B, B, B> t3b;
|
||||
t3b = std::move(t3a);
|
||||
VERIFY( std::get<0>(t3b).v );
|
||||
VERIFY( std::get<1>(t3b).v );
|
||||
VERIFY( std::get<2>(t3b).v );
|
||||
|
||||
// template<class U1, class U2>
|
||||
// constexpr const tuple& operator=(pair<U1, U2>&&) const;
|
||||
|
||||
pair<A, A> p2a;
|
||||
const tuple<B, B> p2b;
|
||||
p2b = std::move(p2a);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test07()
|
||||
{
|
||||
struct B
|
||||
{
|
||||
mutable bool v;
|
||||
constexpr const B& operator=(const B&) const { v = true; return *this; }
|
||||
};
|
||||
|
||||
// constexpr const tuple& operator=(const tuple&) const;
|
||||
|
||||
const tuple<B> t1a;
|
||||
const tuple<B> t1b;
|
||||
t1b = t1a;
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
const tuple<B, B> t2a;
|
||||
const tuple<B, B> t2b;
|
||||
t2b = t2a;
|
||||
VERIFY( std::get<0>(t2b).v );
|
||||
VERIFY( std::get<1>(t2b).v );
|
||||
|
||||
const tuple<B, B, B> t3a;
|
||||
const tuple<B, B, B> t3b;
|
||||
t3b = t3a;
|
||||
VERIFY( std::get<0>(t3b).v );
|
||||
VERIFY( std::get<1>(t3b).v );
|
||||
VERIFY( std::get<2>(t3b).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test08()
|
||||
{
|
||||
struct B
|
||||
{
|
||||
mutable bool v;
|
||||
constexpr const B& operator=(B&&) const { v = true; return *this; }
|
||||
};
|
||||
|
||||
// constexpr const tuple& operator=(tuple&&) const;
|
||||
|
||||
tuple<B> t1a;
|
||||
const tuple<B> t1b;
|
||||
t1b = std::move(t1a);
|
||||
VERIFY( std::get<0>(t1b).v );
|
||||
|
||||
tuple<B, B> t2a;
|
||||
const tuple<B, B> t2b;
|
||||
t2b = std::move(t2a);
|
||||
VERIFY( std::get<0>(t2b).v );
|
||||
VERIFY( std::get<1>(t2b).v );
|
||||
|
||||
tuple<B, B, B> t3a;
|
||||
const tuple<B, B, B> t3b;
|
||||
t3b = std::move(t3a);
|
||||
VERIFY( std::get<0>(t3b).v );
|
||||
VERIFY( std::get<1>(t3b).v );
|
||||
VERIFY( std::get<2>(t3b).v );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct S
|
||||
{
|
||||
mutable int v = 0;
|
||||
friend constexpr void swap(S&& x, S&& y) = delete;
|
||||
friend constexpr void swap(const S& x, const S& y) { ++x.v; ++y.v; }
|
||||
};
|
||||
|
||||
constexpr bool
|
||||
test09()
|
||||
{
|
||||
const tuple<S> t1, u1;
|
||||
std::swap(t1, u1);
|
||||
VERIFY( std::get<0>(t1).v == 1 );
|
||||
VERIFY( std::get<0>(u1).v == 1 );
|
||||
|
||||
const tuple<S, S> t2, u2;
|
||||
std::swap(t2, u2);
|
||||
VERIFY( std::get<0>(t2).v == 1 );
|
||||
VERIFY( std::get<0>(u2).v == 1 );
|
||||
VERIFY( std::get<1>(t2).v == 1 );
|
||||
VERIFY( std::get<1>(u2).v == 1 );
|
||||
|
||||
const tuple<S, S, S> t3, u3;
|
||||
std::swap(t3, u3);
|
||||
VERIFY( std::get<0>(t3).v == 1 );
|
||||
VERIFY( std::get<0>(u3).v == 1 );
|
||||
VERIFY( std::get<1>(t3).v == 1 );
|
||||
VERIFY( std::get<1>(u3).v == 1 );
|
||||
VERIFY( std::get<2>(t3).v == 1 );
|
||||
VERIFY( std::get<2>(u3).v == 1 );
|
||||
|
||||
static_assert(!std::is_swappable_v<const tuple<A>&>);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
static_assert(test01());
|
||||
static_assert(alloc::test01());
|
||||
static_assert(test02());
|
||||
static_assert(alloc::test02());
|
||||
static_assert(test03());
|
||||
static_assert(alloc::test03());
|
||||
static_assert(test04());
|
||||
static_assert(alloc::test04());
|
||||
// FIXME: G++ doesn't support reading mutable members during constexpr (PR c++/92505).
|
||||
test05();
|
||||
test06();
|
||||
test07();
|
||||
test08();
|
||||
test09();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// { dg-options "-std=gnu++23" }
|
||||
// { dg-do compile { target c++23 } }
|
||||
// { dg-xfail-if "not supported" { debug_mode } }
|
||||
|
||||
#include <vector>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
constexpr bool
|
||||
test01()
|
||||
{
|
||||
// P2321R2
|
||||
// constexpr const reference& vector<bool>::operator=(bool x) const noexcept;
|
||||
|
||||
std::vector<bool> v(1);
|
||||
const auto e = v[0];
|
||||
e = true;
|
||||
VERIFY( v[0] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
static_assert(test01());
|
||||
}
|
Loading…
Add table
Reference in a new issue