libstdc++: Implement P2165R4 changes to std::pair/tuple/etc [PR113309]
This implements the C++23 paper P2165R4 Compatibility between tuple, pair and tuple-like objects, which builds upon many changes from the earlier C++23 paper P2321R2 zip. Some declarations had to be moved around so that they're visible from <bits/stl_pair.h> without introducing new includes and bloating the header. In the end, the only new include is for <bits/utility.h> from <bits/stl_iterator.h>, for tuple_element_t. PR libstdc++/113309 PR libstdc++/109203 libstdc++-v3/ChangeLog: * include/bits/ranges_util.h (__detail::__pair_like): Don't define in C++23 mode. (__detail::__pair_like_convertible_from): Adjust as per P2165R4. (__detail::__is_subrange<subrange>): Moved from <ranges>. (__detail::__is_tuple_like_v<subrange>): Likewise. * include/bits/stl_iterator.h: Include <bits/utility.h> for C++23. (__different_from): Move to <concepts>. (__iter_key_t): Adjust for C++23 as per P2165R4. (__iter_val_t): Likewise. * include/bits/stl_pair.h (pair, array): Forward declare. (get): Forward declare all overloads relevant to P2165R4 tuple-like constructors. (__is_tuple_v): Define for C++23. (__is_tuple_like_v): Define for C++23. (__tuple_like): Define for C++23 as per P2165R4. (__pair_like): Define for C++23 as per P2165R4. (__eligibile_tuple_like): Define for C++23. (__eligibile_pair_like): Define for C++23. (pair::_S_constructible_from_pair_like): Define for C++23. (pair::_S_convertible_from_pair_like): Define for C++23. (pair::_S_dangles_from_pair_like): Define for C++23. (pair::pair): Define overloads taking a tuple-like type for C++23 as per P2165R4. (pair::_S_assignable_from_tuple_like): Define for C++23. (pair::_S_const_assignable_from_tuple_like): Define for C++23. (pair::operator=): Define overloads taking a tuple-like type for C++23 as per P2165R4. * include/bits/utility.h (ranges::__detail::__is_subrange): Moved from <ranges>. * include/bits/version.def (tuple_like): Define for C++23. * include/bits/version.h: Regenerate. * include/std/concepts (__different_from): Moved from <bits/stl_iterator.h>. (ranges::__swap::__adl_swap): Clarify which __detail namespace. * include/std/map (__cpp_lib_tuple_like): Define C++23. * include/std/ranges (__detail::__is_subrange): Moved to <bits/utility.h>. (__detail::__is_subrange<subrange>): Moved to <bits/ranges_util.h> (__detail::__has_tuple_element): Adjust for C++23 as per P2165R4. (__detail::__tuple_or_pair): Remove as per P2165R4. Replace all uses with plain tuple as per P2165R4. * include/std/tuple (__cpp_lib_tuple_like): Define for C++23. (__tuple_like_tag_t): Define for C++23. (__tuple_cmp): Forward declare for C++23. (_Tuple_impl::_Tuple_impl): Define overloads taking __tuple_like_tag_t and a tuple-like type for C++23. (_Tuple_impl::_M_assign): Likewise. (tuple::__constructible_from_tuple_like): Define for C++23. (tuple::__convertible_from_tuple_like): Define for C++23. (tuple::__dangles_from_tuple_like): Define for C++23. (tuple::tuple): Define overloads taking a tuple-like type for C++23 as per P2165R4. (tuple::__assignable_from_tuple_like): Define for C++23. (tuple::__const_assignable_from_tuple_like): Define for C++23. (tuple::operator=): Define overloads taking a tuple-like type for C++23 as per P2165R4. (tuple::__tuple_like_common_comparison_category): Define for C++23. (tuple::operator<=>): Define overload taking a tuple-like type for C++23 as per P2165R4. (array, get): Forward declarations moved to <bits/stl_pair.h>. (tuple_cat): Constrain with __tuple_like for C++23 as per P2165R4. (apply): Likewise. (make_from_tuple): Likewise. (__tuple_like_common_reference): Define for C++23. (basic_common_reference): Adjust as per P2165R4. (__tuple_like_common_type): Define for C++23. (common_type): Adjust as per P2165R4. * include/std/unordered_map (__cpp_lib_tuple_like): Define for C++23. * include/std/utility (__cpp_lib_tuple_like): Define for C++23. * testsuite/std/ranges/zip/1.cc (test01): Adjust to handle pair and 2-tuple interchangeably. (test05): New test. * testsuite/20_util/pair/p2165r4.cc: New test. * testsuite/20_util/tuple/p2165r4.cc: New test. Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
This commit is contained in:
parent
87d162383e
commit
65b4cba9d6
15 changed files with 1070 additions and 83 deletions
|
@ -224,6 +224,10 @@ namespace ranges
|
|||
&& !__uses_nonqualification_pointer_conversion<decay_t<_From>,
|
||||
decay_t<_To>>;
|
||||
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
// P2165R4 version of __pair_like is defined in <bits/stl_pair.h>.
|
||||
#else
|
||||
// C++20 version of __pair_like from P2321R2.
|
||||
template<typename _Tp>
|
||||
concept __pair_like
|
||||
= !is_reference_v<_Tp> && requires(_Tp __t)
|
||||
|
@ -235,10 +239,11 @@ namespace ranges
|
|||
{ get<0>(__t) } -> convertible_to<const tuple_element_t<0, _Tp>&>;
|
||||
{ get<1>(__t) } -> convertible_to<const tuple_element_t<1, _Tp>&>;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename _Tp, typename _Up, typename _Vp>
|
||||
concept __pair_like_convertible_from
|
||||
= !range<_Tp> && __pair_like<_Tp>
|
||||
= !range<_Tp> && !is_reference_v<_Vp> && __pair_like<_Tp>
|
||||
&& constructible_from<_Tp, _Up, _Vp>
|
||||
&& __convertible_to_non_slicing<_Up, tuple_element_t<0, _Tp>>
|
||||
&& convertible_to<_Vp, tuple_element_t<1, _Tp>>;
|
||||
|
@ -463,8 +468,18 @@ namespace ranges
|
|||
using borrowed_subrange_t = __conditional_t<borrowed_range<_Range>,
|
||||
subrange<iterator_t<_Range>>,
|
||||
dangling>;
|
||||
|
||||
// __is_subrange is defined in <bits/utility.h>.
|
||||
template<typename _Iter, typename _Sent, subrange_kind _Kind>
|
||||
inline constexpr bool __detail::__is_subrange<subrange<_Iter, _Sent, _Kind>> = true;
|
||||
} // namespace ranges
|
||||
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
// __is_tuple_like_v is defined in <bits/stl_pair.h>.
|
||||
template<typename _It, typename _Sent, ranges::subrange_kind _Kind>
|
||||
inline constexpr bool __is_tuple_like_v<ranges::subrange<_It, _Sent, _Kind>> = true;
|
||||
#endif
|
||||
|
||||
// The following ranges algorithms are used by <ranges>, and are defined here
|
||||
// so that <ranges> can avoid including all of <bits/ranges_algo.h>.
|
||||
namespace ranges
|
||||
|
|
|
@ -78,6 +78,10 @@
|
|||
# include <bits/stl_construct.h>
|
||||
#endif
|
||||
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
# include <bits/utility.h> // for tuple_element_t
|
||||
#endif
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
@ -95,10 +99,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
template<typename _Cat, typename _Limit, typename _Otherwise = _Cat>
|
||||
using __clamp_iter_cat
|
||||
= __conditional_t<derived_from<_Cat, _Limit>, _Limit, _Otherwise>;
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
concept __different_from
|
||||
= !same_as<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2983,11 +2983,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
// of associative containers.
|
||||
template<typename _InputIterator>
|
||||
using __iter_key_t = remove_const_t<
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
tuple_element_t<0, typename iterator_traits<_InputIterator>::value_type>>;
|
||||
#else
|
||||
typename iterator_traits<_InputIterator>::value_type::first_type>;
|
||||
#endif
|
||||
|
||||
template<typename _InputIterator>
|
||||
using __iter_val_t
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
= tuple_element_t<1, typename iterator_traits<_InputIterator>::value_type>;
|
||||
#else
|
||||
= typename iterator_traits<_InputIterator>::value_type::second_type;
|
||||
#endif
|
||||
|
||||
template<typename _T1, typename _T2>
|
||||
struct pair;
|
||||
|
|
|
@ -85,12 +85,70 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
/// @cond undocumented
|
||||
|
||||
// Forward declarations.
|
||||
template<typename _T1, typename _T2>
|
||||
struct pair;
|
||||
|
||||
template<typename...>
|
||||
class tuple;
|
||||
|
||||
// Declarations of std::array and its std::get overloads, so that
|
||||
// std::tuple_cat can use them if <tuple> is included before <array>.
|
||||
// We also declare the other std::get overloads here so that they're
|
||||
// visible to the P2165R4 tuple-like constructors of pair and tuple.
|
||||
template<typename _Tp, size_t _Nm>
|
||||
struct array;
|
||||
|
||||
template<size_t...>
|
||||
struct _Index_tuple;
|
||||
|
||||
template<size_t _Int, class _Tp1, class _Tp2>
|
||||
constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
|
||||
get(pair<_Tp1, _Tp2>& __in) noexcept;
|
||||
|
||||
template<size_t _Int, class _Tp1, class _Tp2>
|
||||
constexpr typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
|
||||
get(pair<_Tp1, _Tp2>&& __in) noexcept;
|
||||
|
||||
template<size_t _Int, class _Tp1, class _Tp2>
|
||||
constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&
|
||||
get(const pair<_Tp1, _Tp2>& __in) noexcept;
|
||||
|
||||
template<size_t _Int, class _Tp1, class _Tp2>
|
||||
constexpr const typename tuple_element<_Int, pair<_Tp1, _Tp2>>::type&&
|
||||
get(const pair<_Tp1, _Tp2>&& __in) noexcept;
|
||||
|
||||
template<size_t __i, typename... _Elements>
|
||||
constexpr __tuple_element_t<__i, tuple<_Elements...>>&
|
||||
get(tuple<_Elements...>& __t) noexcept;
|
||||
|
||||
template<size_t __i, typename... _Elements>
|
||||
constexpr const __tuple_element_t<__i, tuple<_Elements...>>&
|
||||
get(const tuple<_Elements...>& __t) noexcept;
|
||||
|
||||
template<size_t __i, typename... _Elements>
|
||||
constexpr __tuple_element_t<__i, tuple<_Elements...>>&&
|
||||
get(tuple<_Elements...>&& __t) noexcept;
|
||||
|
||||
template<size_t __i, typename... _Elements>
|
||||
constexpr const __tuple_element_t<__i, tuple<_Elements...>>&&
|
||||
get(const tuple<_Elements...>&& __t) noexcept;
|
||||
|
||||
template<size_t _Int, typename _Tp, size_t _Nm>
|
||||
constexpr _Tp&
|
||||
get(array<_Tp, _Nm>&) noexcept;
|
||||
|
||||
template<size_t _Int, typename _Tp, size_t _Nm>
|
||||
constexpr _Tp&&
|
||||
get(array<_Tp, _Nm>&&) noexcept;
|
||||
|
||||
template<size_t _Int, typename _Tp, size_t _Nm>
|
||||
constexpr const _Tp&
|
||||
get(const array<_Tp, _Nm>&) noexcept;
|
||||
|
||||
template<size_t _Int, typename _Tp, size_t _Nm>
|
||||
constexpr const _Tp&&
|
||||
get(const array<_Tp, _Nm>&&) noexcept;
|
||||
|
||||
#if ! __cpp_lib_concepts
|
||||
// Concept utility functions, reused in conditionally-explicit
|
||||
// constructors.
|
||||
|
@ -159,6 +217,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif // lib concepts
|
||||
#endif // C++11
|
||||
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
template<typename _Tp>
|
||||
inline constexpr bool __is_tuple_v = false;
|
||||
|
||||
template<typename... _Ts>
|
||||
inline constexpr bool __is_tuple_v<tuple<_Ts...>> = true;
|
||||
|
||||
// TODO: Reuse __is_tuple_like from <type_traits>?
|
||||
template<typename _Tp>
|
||||
inline constexpr bool __is_tuple_like_v = false;
|
||||
|
||||
template<typename... _Elements>
|
||||
inline constexpr bool __is_tuple_like_v<tuple<_Elements...>> = true;
|
||||
|
||||
template<typename _T1, typename _T2>
|
||||
inline constexpr bool __is_tuple_like_v<pair<_T1, _T2>> = true;
|
||||
|
||||
template<typename _Tp, size_t _Nm>
|
||||
inline constexpr bool __is_tuple_like_v<array<_Tp, _Nm>> = true;
|
||||
|
||||
// __is_tuple_like_v<subrange> is defined in <bits/ranges_util.h>.
|
||||
|
||||
template<typename _Tp>
|
||||
concept __tuple_like = __is_tuple_like_v<remove_cvref_t<_Tp>>;
|
||||
|
||||
template<typename _Tp>
|
||||
concept __pair_like = __tuple_like<_Tp> && tuple_size_v<remove_cvref_t<_Tp>> == 2;
|
||||
|
||||
template<typename _Tp, typename _Tuple>
|
||||
concept __eligible_tuple_like
|
||||
= __detail::__different_from<_Tp, _Tuple> && __tuple_like<_Tp>
|
||||
&& (tuple_size_v<remove_cvref_t<_Tp>> == tuple_size_v<_Tuple>)
|
||||
&& !ranges::__detail::__is_subrange<remove_cvref_t<_Tp>>;
|
||||
|
||||
template<typename _Tp, typename _Pair>
|
||||
concept __eligible_pair_like
|
||||
= __detail::__different_from<_Tp, _Pair> && __pair_like<_Tp>
|
||||
&& !ranges::__detail::__is_subrange<remove_cvref_t<_Tp>>;
|
||||
#endif // C++23
|
||||
|
||||
template<typename _U1, typename _U2> class __pair_base
|
||||
{
|
||||
#if __cplusplus >= 201103L && ! __cpp_lib_concepts
|
||||
|
@ -295,6 +393,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
template<typename _UPair>
|
||||
static constexpr bool
|
||||
_S_constructible_from_pair_like()
|
||||
{
|
||||
return _S_constructible<decltype(std::get<0>(std::declval<_UPair>())),
|
||||
decltype(std::get<1>(std::declval<_UPair>()))>();
|
||||
}
|
||||
|
||||
template<typename _UPair>
|
||||
static constexpr bool
|
||||
_S_convertible_from_pair_like()
|
||||
{
|
||||
return _S_convertible<decltype(std::get<0>(std::declval<_UPair>())),
|
||||
decltype(std::get<1>(std::declval<_UPair>()))>();
|
||||
}
|
||||
|
||||
template<typename _UPair>
|
||||
static constexpr bool
|
||||
_S_dangles_from_pair_like()
|
||||
{
|
||||
return _S_dangles<decltype(std::get<0>(std::declval<_UPair>())),
|
||||
decltype(std::get<1>(std::declval<_UPair>()))>();
|
||||
}
|
||||
#endif // C++23
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
|
@ -393,6 +517,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
pair(const pair<_U1, _U2>&&) = delete;
|
||||
#endif // C++23
|
||||
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
template<__eligible_pair_like<pair> _UPair>
|
||||
requires (_S_constructible_from_pair_like<_UPair>())
|
||||
&& (!_S_dangles_from_pair_like<_UPair>())
|
||||
constexpr explicit(!_S_convertible_from_pair_like<_UPair>())
|
||||
pair(_UPair&& __p)
|
||||
: first(std::get<0>(std::forward<_UPair>(__p))),
|
||||
second(std::get<1>(std::forward<_UPair>(__p)))
|
||||
{ }
|
||||
|
||||
template<__eligible_pair_like<pair> _UPair>
|
||||
requires (_S_constructible_from_pair_like<_UPair>())
|
||||
&& (_S_dangles_from_pair_like<_UPair>())
|
||||
constexpr explicit(!_S_convertible_from_pair_like<_UPair>())
|
||||
pair(_UPair&&) = delete;
|
||||
#endif // C++23
|
||||
|
||||
private:
|
||||
/// @cond undocumented
|
||||
template<typename _U1, typename _U2>
|
||||
|
@ -421,6 +562,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return is_nothrow_assignable_v<_T2&, _U2>;
|
||||
return false;
|
||||
}
|
||||
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
template<typename _UPair>
|
||||
static constexpr bool
|
||||
_S_assignable_from_tuple_like()
|
||||
{
|
||||
return _S_assignable<decltype(std::get<0>(std::declval<_UPair>())),
|
||||
decltype(std::get<1>(std::declval<_UPair>()))>();
|
||||
}
|
||||
|
||||
template<typename _UPair>
|
||||
static constexpr bool
|
||||
_S_const_assignable_from_tuple_like()
|
||||
{
|
||||
return _S_const_assignable<decltype(std::get<0>(std::declval<_UPair>())),
|
||||
decltype(std::get<1>(std::declval<_UPair>()))>();
|
||||
}
|
||||
#endif // C++23
|
||||
/// @endcond
|
||||
|
||||
public:
|
||||
|
@ -516,6 +675,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
return *this;
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
#if __glibcxx_tuple_like // >= C++23
|
||||
template<__eligible_pair_like<pair> _UPair>
|
||||
requires (_S_assignable_from_tuple_like<_UPair>())
|
||||
constexpr pair&
|
||||
operator=(_UPair&& __p)
|
||||
{
|
||||
first = std::get<0>(std::forward<_UPair>(__p));
|
||||
second = std::get<1>(std::forward<_UPair>(__p));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<__eligible_pair_like<pair> _UPair>
|
||||
requires (_S_const_assignable_from_tuple_like<_UPair>())
|
||||
constexpr const pair&
|
||||
operator=(_UPair&& __p) const
|
||||
{
|
||||
first = std::get<0>(std::forward<_UPair>(__p));
|
||||
second = std::get<1>(std::forward<_UPair>(__p));
|
||||
return *this;
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
#else // !__cpp_lib_concepts
|
||||
// C++11/14/17 implementation using enable_if, partially constexpr.
|
||||
|
||||
|
|
|
@ -266,6 +266,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if __glibcxx_ranges
|
||||
namespace ranges::__detail
|
||||
{
|
||||
template<typename _Range>
|
||||
inline constexpr bool __is_subrange = false;
|
||||
} // namespace __detail
|
||||
#endif
|
||||
|
||||
_GLIBCXX_END_NAMESPACE_VERSION
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -1780,6 +1780,14 @@ ftms = {
|
|||
};
|
||||
};
|
||||
|
||||
ftms = {
|
||||
name = tuple_like;
|
||||
values = {
|
||||
v = 202207;
|
||||
cxxmin = 23;
|
||||
};
|
||||
};
|
||||
|
||||
// Standard test specifications.
|
||||
stds[97] = ">= 199711L";
|
||||
stds[03] = ">= 199711L";
|
||||
|
|
|
@ -1983,4 +1983,14 @@
|
|||
#endif /* !defined(__cpp_lib_generator) && defined(__glibcxx_want_generator) */
|
||||
#undef __glibcxx_want_generator
|
||||
|
||||
#if !defined(__cpp_lib_tuple_like)
|
||||
# if (__cplusplus >= 202100L)
|
||||
# define __glibcxx_tuple_like 202207L
|
||||
# if defined(__glibcxx_want_all) || defined(__glibcxx_want_tuple_like)
|
||||
# define __cpp_lib_tuple_like 202207L
|
||||
# endif
|
||||
# endif
|
||||
#endif /* !defined(__cpp_lib_tuple_like) && defined(__glibcxx_want_tuple_like) */
|
||||
#undef __glibcxx_want_tuple_like
|
||||
|
||||
#undef __glibcxx_want_all
|
||||
|
|
|
@ -62,6 +62,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
concept same_as
|
||||
= __detail::__same_as<_Tp, _Up> && __detail::__same_as<_Up, _Tp>;
|
||||
|
||||
namespace __detail
|
||||
{
|
||||
template<typename _Tp, typename _Up>
|
||||
concept __different_from
|
||||
= !same_as<remove_cvref_t<_Tp>, remove_cvref_t<_Up>>;
|
||||
} // namespace __detail
|
||||
|
||||
/// [concept.derived], concept derived_from
|
||||
template<typename _Derived, typename _Base>
|
||||
concept derived_from = __is_base_of(_Base, _Derived)
|
||||
|
@ -185,8 +192,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
template<typename _Tp, typename _Up>
|
||||
concept __adl_swap
|
||||
= (__detail::__class_or_enum<remove_reference_t<_Tp>>
|
||||
|| __detail::__class_or_enum<remove_reference_t<_Up>>)
|
||||
= (std::__detail::__class_or_enum<remove_reference_t<_Tp>>
|
||||
|| std::__detail::__class_or_enum<remove_reference_t<_Up>>)
|
||||
&& requires(_Tp&& __t, _Up&& __u) {
|
||||
swap(static_cast<_Tp&&>(__t), static_cast<_Up&&>(__u));
|
||||
};
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#define __glibcxx_want_map_try_emplace
|
||||
#define __glibcxx_want_node_extract
|
||||
#define __glibcxx_want_nonmember_container_access
|
||||
#define __glibcxx_want_tuple_like
|
||||
#include <bits/version.h>
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
|
|
|
@ -2389,11 +2389,7 @@ namespace views::__adaptor
|
|||
inline constexpr bool __is_basic_string_view<basic_string_view<_CharT, _Traits>>
|
||||
= true;
|
||||
|
||||
template<typename _Range>
|
||||
inline constexpr bool __is_subrange = false;
|
||||
|
||||
template<typename _Iter, typename _Sent, subrange_kind _Kind>
|
||||
inline constexpr bool __is_subrange<subrange<_Iter, _Sent, _Kind>> = true;
|
||||
using ranges::__detail::__is_subrange;
|
||||
|
||||
template<typename _Range>
|
||||
inline constexpr bool __is_iota_view = false;
|
||||
|
@ -4166,6 +4162,10 @@ namespace views::__adaptor
|
|||
|
||||
namespace __detail
|
||||
{
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _Tp, size_t _Nm>
|
||||
concept __has_tuple_element = __tuple_like<_Tp> && _Nm < tuple_size_v<_Tp>;
|
||||
#else
|
||||
template<typename _Tp, size_t _Nm>
|
||||
concept __has_tuple_element = requires(_Tp __t)
|
||||
{
|
||||
|
@ -4175,6 +4175,7 @@ namespace views::__adaptor
|
|||
{ std::get<_Nm>(__t) }
|
||||
-> convertible_to<const tuple_element_t<_Nm, _Tp>&>;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename _Tp, size_t _Nm>
|
||||
concept __returnable_element
|
||||
|
@ -4559,23 +4560,12 @@ namespace views::__adaptor
|
|||
|| (!(bidirectional_range<_Rs> && ...) && (common_range<_Rs> && ...))
|
||||
|| ((random_access_range<_Rs> && ...) && (sized_range<_Rs> && ...));
|
||||
|
||||
template<typename... _Ts>
|
||||
struct __tuple_or_pair
|
||||
{ using type = std::tuple<_Ts...>; };
|
||||
|
||||
template<typename _Tp, typename _Up>
|
||||
struct __tuple_or_pair<_Tp, _Up>
|
||||
{ using type = pair<_Tp, _Up>; };
|
||||
|
||||
template<typename... _Ts>
|
||||
using __tuple_or_pair_t = typename __tuple_or_pair<_Ts...>::type;
|
||||
|
||||
template<typename _Fp, typename _Tuple>
|
||||
constexpr auto
|
||||
__tuple_transform(_Fp&& __f, _Tuple&& __tuple)
|
||||
{
|
||||
return std::apply([&]<typename... _Ts>(_Ts&&... __elts) {
|
||||
return __tuple_or_pair_t<invoke_result_t<_Fp&, _Ts>...>
|
||||
return tuple<invoke_result_t<_Fp&, _Ts>...>
|
||||
(std::__invoke(__f, std::forward<_Ts>(__elts))...);
|
||||
}, std::forward<_Tuple>(__tuple));
|
||||
}
|
||||
|
@ -4696,7 +4686,7 @@ namespace views::__adaptor
|
|||
#ifdef __clang__ // LLVM-61763 workaround
|
||||
public:
|
||||
#endif
|
||||
__detail::__tuple_or_pair_t<iterator_t<__detail::__maybe_const_t<_Const, _Vs>>...> _M_current;
|
||||
tuple<iterator_t<__detail::__maybe_const_t<_Const, _Vs>>...> _M_current;
|
||||
|
||||
constexpr explicit
|
||||
_Iterator(decltype(_M_current) __current)
|
||||
|
@ -4728,7 +4718,7 @@ namespace views::__adaptor
|
|||
// iterator_category defined in __zip_view_iter_cat
|
||||
using iterator_concept = decltype(_S_iter_concept());
|
||||
using value_type
|
||||
= __detail::__tuple_or_pair_t<range_value_t<__detail::__maybe_const_t<_Const, _Vs>>...>;
|
||||
= tuple<range_value_t<__detail::__maybe_const_t<_Const, _Vs>>...>;
|
||||
using difference_type
|
||||
= common_type_t<range_difference_t<__detail::__maybe_const_t<_Const, _Vs>>...>;
|
||||
|
||||
|
@ -4900,7 +4890,7 @@ namespace views::__adaptor
|
|||
template<bool _Const>
|
||||
class zip_view<_Vs...>::_Sentinel
|
||||
{
|
||||
__detail::__tuple_or_pair_t<sentinel_t<__detail::__maybe_const_t<_Const, _Vs>>...> _M_end;
|
||||
tuple<sentinel_t<__detail::__maybe_const_t<_Const, _Vs>>...> _M_end;
|
||||
|
||||
constexpr explicit
|
||||
_Sentinel(decltype(_M_end) __end)
|
||||
|
@ -8325,8 +8315,7 @@ namespace views::__adaptor
|
|||
&& __detail::__cartesian_product_is_common<_First, _Vs...>)
|
||||
{
|
||||
auto __its = [this]<size_t... _Is>(index_sequence<_Is...>) {
|
||||
using _Ret = __detail::__tuple_or_pair_t<iterator_t<_First>,
|
||||
iterator_t<_Vs>...>;
|
||||
using _Ret = tuple<iterator_t<_First>, iterator_t<_Vs>...>;
|
||||
bool __empty_tail = (ranges::empty(std::get<1 + _Is>(_M_bases)) || ...);
|
||||
auto& __first = std::get<0>(_M_bases);
|
||||
return _Ret{(__empty_tail
|
||||
|
@ -8342,8 +8331,7 @@ namespace views::__adaptor
|
|||
end() const requires __detail::__cartesian_product_is_common<const _First, const _Vs...>
|
||||
{
|
||||
auto __its = [this]<size_t... _Is>(index_sequence<_Is...>) {
|
||||
using _Ret = __detail::__tuple_or_pair_t<iterator_t<const _First>,
|
||||
iterator_t<const _Vs>...>;
|
||||
using _Ret = tuple<iterator_t<const _First>, iterator_t<const _Vs>...>;
|
||||
bool __empty_tail = (ranges::empty(std::get<1 + _Is>(_M_bases)) || ...);
|
||||
auto& __first = std::get<0>(_M_bases);
|
||||
return _Ret{(__empty_tail
|
||||
|
@ -8416,8 +8404,8 @@ namespace views::__adaptor
|
|||
{
|
||||
using _Parent = __maybe_const_t<_Const, cartesian_product_view>;
|
||||
_Parent* _M_parent = nullptr;
|
||||
__detail::__tuple_or_pair_t<iterator_t<__maybe_const_t<_Const, _First>>,
|
||||
iterator_t<__maybe_const_t<_Const, _Vs>>...> _M_current;
|
||||
tuple<iterator_t<__maybe_const_t<_Const, _First>>,
|
||||
iterator_t<__maybe_const_t<_Const, _Vs>>...> _M_current;
|
||||
|
||||
constexpr
|
||||
_Iterator(_Parent& __parent, decltype(_M_current) __current)
|
||||
|
@ -8444,11 +8432,11 @@ namespace views::__adaptor
|
|||
using iterator_category = input_iterator_tag;
|
||||
using iterator_concept = decltype(_S_iter_concept());
|
||||
using value_type
|
||||
= __detail::__tuple_or_pair_t<range_value_t<__maybe_const_t<_Const, _First>>,
|
||||
range_value_t<__maybe_const_t<_Const, _Vs>>...>;
|
||||
= tuple<range_value_t<__maybe_const_t<_Const, _First>>,
|
||||
range_value_t<__maybe_const_t<_Const, _Vs>>...>;
|
||||
using reference
|
||||
= __detail::__tuple_or_pair_t<range_reference_t<__maybe_const_t<_Const, _First>>,
|
||||
range_reference_t<__maybe_const_t<_Const, _Vs>>...>;
|
||||
= tuple<range_reference_t<__maybe_const_t<_Const, _First>>,
|
||||
range_reference_t<__maybe_const_t<_Const, _Vs>>...>;
|
||||
using difference_type = decltype(cartesian_product_view::_S_difference_type());
|
||||
|
||||
_Iterator() = default;
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#define __glibcxx_want_apply
|
||||
#define __glibcxx_want_make_from_tuple
|
||||
#define __glibcxx_want_ranges_zip
|
||||
#define __glibcxx_want_tuple_like
|
||||
#include <bits/version.h>
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
|
@ -246,6 +247,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
_Head _M_head_impl;
|
||||
};
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
struct __tuple_like_tag_t { explicit __tuple_like_tag_t() = default; };
|
||||
|
||||
// These forward declarations are used by the operator<=> overload for
|
||||
// tuple-like types.
|
||||
template<typename _Cat, typename _Tp, typename _Up>
|
||||
constexpr _Cat
|
||||
__tuple_cmp(const _Tp&, const _Up&, index_sequence<>);
|
||||
|
||||
template<typename _Cat, typename _Tp, typename _Up,
|
||||
size_t _Idx0, size_t... _Idxs>
|
||||
constexpr _Cat
|
||||
__tuple_cmp(const _Tp& __t, const _Up& __u,
|
||||
index_sequence<_Idx0, _Idxs...>);
|
||||
#endif // C++23
|
||||
|
||||
/**
|
||||
* Contains the actual implementation of the @c tuple template, stored
|
||||
* as a recursive inheritance hierarchy from the first element (most
|
||||
|
@ -342,6 +359,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ }
|
||||
#endif // C++23
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _UTuple, size_t... _Is>
|
||||
constexpr
|
||||
_Tuple_impl(__tuple_like_tag_t, _UTuple&& __u, index_sequence<_Is...>)
|
||||
: _Tuple_impl(std::get<_Is>(std::forward<_UTuple>(__u))...)
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
template<typename _Alloc>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a)
|
||||
|
@ -428,6 +453,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ }
|
||||
#endif // C++23
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _Alloc, typename _UTuple, size_t... _Is>
|
||||
constexpr
|
||||
_Tuple_impl(__tuple_like_tag_t, allocator_arg_t __tag, const _Alloc& __a,
|
||||
_UTuple&& __u, index_sequence<_Is...>)
|
||||
: _Tuple_impl(__tag, __a, std::get<_Is>(std::forward<_UTuple>(__u))...)
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
template<typename... _UElements>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
|
@ -470,6 +504,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
#endif // C++23
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _UTuple>
|
||||
constexpr void
|
||||
_M_assign(__tuple_like_tag_t __tag, _UTuple&& __u)
|
||||
{
|
||||
_M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u));
|
||||
_M_tail(*this)._M_assign(__tag, std::forward<_UTuple>(__u));
|
||||
}
|
||||
|
||||
template<typename _UTuple>
|
||||
constexpr void
|
||||
_M_assign(__tuple_like_tag_t __tag, _UTuple&& __u) const
|
||||
{
|
||||
_M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u));
|
||||
_M_tail(*this)._M_assign(__tag, std::forward<_UTuple>(__u));
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
protected:
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
|
@ -563,6 +615,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ }
|
||||
#endif // C++23
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _UTuple>
|
||||
constexpr
|
||||
_Tuple_impl(__tuple_like_tag_t, _UTuple&& __u, index_sequence<0>)
|
||||
: _Tuple_impl(std::get<0>(std::forward<_UTuple>(__u)))
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
template<typename _Alloc>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
_Tuple_impl(allocator_arg_t __tag, const _Alloc& __a)
|
||||
|
@ -633,6 +693,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ }
|
||||
#endif // C++23
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _Alloc, typename _UTuple>
|
||||
constexpr
|
||||
_Tuple_impl(__tuple_like_tag_t, allocator_arg_t __tag, const _Alloc& __a,
|
||||
_UTuple&& __u, index_sequence<0>)
|
||||
: _Tuple_impl(__tag, __a, std::get<0>(std::forward<_UTuple>(__u)))
|
||||
{ }
|
||||
#endif // C++23
|
||||
|
||||
template<typename _UHead>
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
|
@ -667,6 +736,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
#endif // C++23
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _UTuple>
|
||||
constexpr void
|
||||
_M_assign(__tuple_like_tag_t, _UTuple&& __u)
|
||||
{ _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); }
|
||||
|
||||
template<typename _UTuple>
|
||||
constexpr void
|
||||
_M_assign(__tuple_like_tag_t, _UTuple&& __u) const
|
||||
{ _M_head(*this) = std::get<_Idx>(std::forward<_UTuple>(__u)); }
|
||||
#endif // C++23
|
||||
|
||||
protected:
|
||||
_GLIBCXX20_CONSTEXPR
|
||||
void
|
||||
|
@ -846,6 +927,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
#endif
|
||||
}
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 4045. tuple can create dangling references from tuple-like
|
||||
template<typename _UTuple>
|
||||
static consteval bool
|
||||
__dangles_from_tuple_like()
|
||||
{
|
||||
return []<size_t... _Is>(index_sequence<_Is...>) {
|
||||
return __dangles<decltype(std::get<_Is>(std::declval<_UTuple>()))...>();
|
||||
}(index_sequence_for<_Elements...>{});
|
||||
}
|
||||
|
||||
template<typename _UTuple>
|
||||
static consteval bool
|
||||
__constructible_from_tuple_like()
|
||||
{
|
||||
return []<size_t... _Is>(index_sequence<_Is...>) {
|
||||
return __constructible<decltype(std::get<_Is>(std::declval<_UTuple>()))...>();
|
||||
}(index_sequence_for<_Elements...>{});
|
||||
}
|
||||
|
||||
template<typename _UTuple>
|
||||
static consteval bool
|
||||
__convertible_from_tuple_like()
|
||||
{
|
||||
return []<size_t... _Is>(index_sequence<_Is...>) {
|
||||
return __convertible<decltype(std::get<_Is>(std::declval<_UTuple>()))...>();
|
||||
}(index_sequence_for<_Elements...>{});
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
public:
|
||||
constexpr
|
||||
explicit(!(__is_implicitly_default_constructible_v<_Elements> && ...))
|
||||
|
@ -1016,10 +1128,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
tuple(const pair<_U1, _U2>&&) = delete;
|
||||
#endif // C++23
|
||||
|
||||
#if 0 && __cpp_lib_tuple_like // >= C++23
|
||||
template<__tuple_like _UTuple>
|
||||
constexpr explicit(...)
|
||||
tuple(_UTuple&& __u);
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<__eligible_tuple_like<tuple> _UTuple>
|
||||
requires (__constructible_from_tuple_like<_UTuple>())
|
||||
&& (!__use_other_ctor<_UTuple>())
|
||||
&& (!__dangles_from_tuple_like<_UTuple>())
|
||||
constexpr explicit(!__convertible_from_tuple_like<_UTuple>())
|
||||
tuple(_UTuple&& __u)
|
||||
: _Inherited(__tuple_like_tag_t{},
|
||||
std::forward<_UTuple>(__u),
|
||||
index_sequence_for<_Elements...>{})
|
||||
{ }
|
||||
|
||||
template<__eligible_tuple_like<tuple> _UTuple>
|
||||
requires (__constructible_from_tuple_like<_UTuple>())
|
||||
&& (!__use_other_ctor<_UTuple>())
|
||||
&& (__dangles_from_tuple_like<_UTuple>())
|
||||
tuple(_UTuple&&) = delete;
|
||||
#endif // C++23
|
||||
|
||||
// Allocator-extended constructors.
|
||||
|
@ -1202,10 +1327,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
tuple(allocator_arg_t, const _Alloc&, const pair<_U1, _U2>&&) = delete;
|
||||
#endif // C++23
|
||||
|
||||
#if 0 && __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _Alloc, __tuple_like _UTuple>
|
||||
constexpr explicit(...)
|
||||
tuple(allocator_arg_t __tag, const _Alloc& __a, _UTuple&& __u);
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _Alloc, __eligible_tuple_like<tuple> _UTuple>
|
||||
requires (__constructible_from_tuple_like<_UTuple>())
|
||||
&& (!__use_other_ctor<_UTuple>())
|
||||
&& (!__dangles_from_tuple_like<_UTuple>())
|
||||
constexpr explicit(!__convertible_from_tuple_like<_UTuple>())
|
||||
tuple(allocator_arg_t __tag, const _Alloc& __a, _UTuple&& __u)
|
||||
: _Inherited(__tuple_like_tag_t{},
|
||||
__tag, __a, std::forward<_UTuple>(__u),
|
||||
index_sequence_for<_Elements...>{})
|
||||
{ }
|
||||
|
||||
template<typename _Alloc, __eligible_tuple_like<tuple> _UTuple>
|
||||
requires (__constructible_from_tuple_like<_UTuple>())
|
||||
&& (!__use_other_ctor<_UTuple>())
|
||||
&& (__dangles_from_tuple_like<_UTuple>())
|
||||
tuple(allocator_arg_t, const _Alloc&, _UTuple&&) = delete;
|
||||
#endif // C++23
|
||||
|
||||
#else // !(concepts && conditional_explicit)
|
||||
|
@ -1539,6 +1677,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
#endif // C++23
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<typename _UTuple>
|
||||
static consteval bool
|
||||
__assignable_from_tuple_like()
|
||||
{
|
||||
return []<size_t... _Is>(index_sequence<_Is...>) {
|
||||
return __assignable<decltype(std::get<_Is>(std::declval<_UTuple>()))...>();
|
||||
}(index_sequence_for<_Elements...>{});
|
||||
}
|
||||
|
||||
template<typename _UTuple>
|
||||
static consteval bool
|
||||
__const_assignable_from_tuple_like()
|
||||
{
|
||||
return []<size_t... _Is>(index_sequence<_Is...>) {
|
||||
return __const_assignable<decltype(std::get<_Is>(std::declval<_UTuple>()))...>();
|
||||
}(index_sequence_for<_Elements...>{});
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
public:
|
||||
|
||||
tuple& operator=(const tuple& __u) = delete;
|
||||
|
@ -1661,14 +1819,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
#endif // C++23
|
||||
|
||||
#if 0 && __cpp_lib_tuple_like // >= C++23
|
||||
template<__tuple_like _UTuple>
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<__eligible_tuple_like<tuple> _UTuple>
|
||||
requires (__assignable_from_tuple_like<_UTuple>())
|
||||
constexpr tuple&
|
||||
operator=(_UTuple&& __u);
|
||||
operator=(_UTuple&& __u)
|
||||
{
|
||||
this->_M_assign(__tuple_like_tag_t{}, std::forward<_UTuple>(__u));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<__eligible_tuple_like<tuple> _UTuple>
|
||||
requires (__const_assignable_from_tuple_like<_UTuple>())
|
||||
constexpr const tuple&
|
||||
operator=(_UTuple&& __u) const
|
||||
{
|
||||
this->_M_assign(__tuple_like_tag_t{}, std::forward<_UTuple>(__u));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<__tuple_like _UTuple>
|
||||
constexpr tuple&
|
||||
operator=(_UTuple&& __u) const;
|
||||
requires (!__is_tuple_v<_UTuple>)
|
||||
friend constexpr bool
|
||||
operator==(const tuple& __t, const _UTuple& __u)
|
||||
{
|
||||
static_assert(sizeof...(_Elements) == tuple_size_v<_UTuple>,
|
||||
"tuple objects can only be compared if they have equal sizes.");
|
||||
return [&]<size_t... _Is>(index_sequence<_Is...>) {
|
||||
return (bool(std::get<_Is>(__t) == std::get<_Is>(__u))
|
||||
&& ...);
|
||||
}(index_sequence_for<_Elements...>{});
|
||||
}
|
||||
|
||||
template<__tuple_like _UTuple,
|
||||
typename = make_index_sequence<tuple_size_v<_UTuple>>>
|
||||
struct __tuple_like_common_comparison_category;
|
||||
|
||||
template<__tuple_like _UTuple, size_t... _Is>
|
||||
requires requires
|
||||
{ typename void_t<__detail::__synth3way_t<_Elements, tuple_element_t<_Is, _UTuple>>...>; }
|
||||
struct __tuple_like_common_comparison_category<_UTuple, index_sequence<_Is...>>
|
||||
{
|
||||
using type = common_comparison_category_t
|
||||
<__detail::__synth3way_t<_Elements, tuple_element_t<_Is, _UTuple>>...>;
|
||||
};
|
||||
|
||||
template<__tuple_like _UTuple>
|
||||
requires (!__is_tuple_v<_UTuple>)
|
||||
friend constexpr typename __tuple_like_common_comparison_category<_UTuple>::type
|
||||
operator<=>(const tuple& __t, const _UTuple& __u)
|
||||
{
|
||||
using _Cat = typename __tuple_like_common_comparison_category<_UTuple>::type;
|
||||
return std::__tuple_cmp<_Cat>(__t, __u, index_sequence_for<_Elements...>());
|
||||
}
|
||||
#endif // C++23
|
||||
|
||||
#else // ! (concepts && consteval)
|
||||
|
@ -2433,27 +2636,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
forward_as_tuple(_Elements&&... __args) noexcept
|
||||
{ return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); }
|
||||
|
||||
// Declarations of std::array and its std::get overloads, so that
|
||||
// std::tuple_cat can use them if <tuple> is included before <array>.
|
||||
|
||||
template<typename _Tp, size_t _Nm> struct array;
|
||||
|
||||
template<size_t _Int, typename _Tp, size_t _Nm>
|
||||
constexpr _Tp&
|
||||
get(array<_Tp, _Nm>&) noexcept;
|
||||
|
||||
template<size_t _Int, typename _Tp, size_t _Nm>
|
||||
constexpr _Tp&&
|
||||
get(array<_Tp, _Nm>&&) noexcept;
|
||||
|
||||
template<size_t _Int, typename _Tp, size_t _Nm>
|
||||
constexpr const _Tp&
|
||||
get(const array<_Tp, _Nm>&) noexcept;
|
||||
|
||||
template<size_t _Int, typename _Tp, size_t _Nm>
|
||||
constexpr const _Tp&&
|
||||
get(const array<_Tp, _Nm>&&) noexcept;
|
||||
|
||||
/// @cond undocumented
|
||||
template<size_t, typename, typename, size_t>
|
||||
struct __make_tuple_impl;
|
||||
|
@ -2569,8 +2751,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
/// @endcond
|
||||
|
||||
/// Create a `tuple` containing all elements from multiple tuple-like objects
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<__tuple_like... _Tpls>
|
||||
#else
|
||||
template<typename... _Tpls, typename = typename
|
||||
enable_if<__and_<__is_tuple_like<_Tpls>...>::value>::type>
|
||||
#endif
|
||||
constexpr auto
|
||||
tuple_cat(_Tpls&&... __tpls)
|
||||
-> typename __tuple_cat_result<_Tpls...>::__type
|
||||
|
@ -2722,7 +2908,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
std::get<_Idx>(std::forward<_Tuple>(__t))...);
|
||||
}
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template <typename _Fn, __tuple_like _Tuple>
|
||||
#else
|
||||
template <typename _Fn, typename _Tuple>
|
||||
#endif
|
||||
constexpr decltype(auto)
|
||||
apply(_Fn&& __f, _Tuple&& __t)
|
||||
noexcept(__unpack_std_tuple<is_nothrow_invocable, _Fn, _Tuple>)
|
||||
|
@ -2741,7 +2931,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
__make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>)
|
||||
{ return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); }
|
||||
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template <typename _Tp, __tuple_like _Tuple>
|
||||
#else
|
||||
template <typename _Tp, typename _Tuple>
|
||||
#endif
|
||||
constexpr _Tp
|
||||
make_from_tuple(_Tuple&& __t)
|
||||
noexcept(__unpack_std_tuple<is_nothrow_constructible, _Tp, _Tuple>)
|
||||
|
@ -2759,17 +2953,60 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
}
|
||||
#endif
|
||||
|
||||
#if __cpp_lib_ranges_zip // >= C++23
|
||||
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>>...>; };
|
||||
#if __cpp_lib_tuple_like // >= C++23
|
||||
template<__tuple_like _TTuple, __tuple_like _UTuple,
|
||||
template<typename> class _TQual, template<typename> class _UQual,
|
||||
typename = make_index_sequence<tuple_size_v<_TTuple>>>
|
||||
struct __tuple_like_common_reference;
|
||||
|
||||
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>...>; };
|
||||
template<__tuple_like _TTuple, __tuple_like _UTuple,
|
||||
template<typename> class _TQual, template<typename> class _UQual,
|
||||
size_t... _Is>
|
||||
requires requires
|
||||
{ typename tuple<common_reference_t<_TQual<tuple_element_t<_Is, _TTuple>>,
|
||||
_UQual<tuple_element_t<_Is, _UTuple>>>...>; }
|
||||
struct __tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual, index_sequence<_Is...>>
|
||||
{
|
||||
using type = tuple<common_reference_t<_TQual<tuple_element_t<_Is, _TTuple>>,
|
||||
_UQual<tuple_element_t<_Is, _UTuple>>>...>;
|
||||
};
|
||||
|
||||
template<__tuple_like _TTuple, __tuple_like _UTuple,
|
||||
template<typename> class _TQual, template<typename> class _UQual>
|
||||
requires (__is_tuple_v<_TTuple> || __is_tuple_v<_UTuple>)
|
||||
&& is_same_v<_TTuple, decay_t<_TTuple>>
|
||||
&& is_same_v<_UTuple, decay_t<_UTuple>>
|
||||
&& (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>)
|
||||
&& requires { typename __tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; }
|
||||
struct basic_common_reference<_TTuple, _UTuple, _TQual, _UQual>
|
||||
{
|
||||
using type = typename __tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type;
|
||||
};
|
||||
|
||||
template<__tuple_like _TTuple, __tuple_like _UTuple,
|
||||
typename = make_index_sequence<tuple_size_v<_TTuple>>>
|
||||
struct __tuple_like_common_type;
|
||||
|
||||
template<__tuple_like _TTuple, __tuple_like _UTuple, size_t... _Is>
|
||||
requires requires
|
||||
{ typename tuple<common_type_t<tuple_element_t<_Is, _TTuple>,
|
||||
tuple_element_t<_Is, _UTuple>>...>; }
|
||||
struct __tuple_like_common_type<_TTuple, _UTuple, index_sequence<_Is...>>
|
||||
{
|
||||
using type = tuple<common_type_t<tuple_element_t<_Is, _TTuple>,
|
||||
tuple_element_t<_Is, _UTuple>>...>;
|
||||
};
|
||||
|
||||
template<__tuple_like _TTuple, __tuple_like _UTuple>
|
||||
requires (__is_tuple_v<_TTuple> || __is_tuple_v<_UTuple>)
|
||||
&& is_same_v<_TTuple, decay_t<_TTuple>>
|
||||
&& is_same_v<_UTuple, decay_t<_UTuple>>
|
||||
&& (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>)
|
||||
&& requires { typename __tuple_like_common_type<_TTuple, _UTuple>::type; }
|
||||
struct common_type<_TTuple, _UTuple>
|
||||
{
|
||||
using type = typename __tuple_like_common_type<_TTuple, _UTuple>::type;
|
||||
};
|
||||
#endif // C++23
|
||||
|
||||
/// @}
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#define __glibcxx_want_node_extract
|
||||
#define __glibcxx_want_nonmember_container_access
|
||||
#define __glibcxx_want_unordered_map_try_emplace
|
||||
#define __glibcxx_want_tuple_like
|
||||
#include <bits/version.h>
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
#define __glibcxx_want_tuple_element_t
|
||||
#define __glibcxx_want_tuples_by_type
|
||||
#define __glibcxx_want_unreachable
|
||||
#define __glibcxx_want_tuple_like
|
||||
#include <bits/version.h>
|
||||
|
||||
namespace std _GLIBCXX_VISIBILITY(default)
|
||||
|
|
173
libstdc++-v3/testsuite/20_util/pair/p2165r4.cc
Normal file
173
libstdc++-v3/testsuite/20_util/pair/p2165r4.cc
Normal file
|
@ -0,0 +1,173 @@
|
|||
// Verify P2165R4 enhancements to std::pair.
|
||||
// { dg-do run { target c++23 } }
|
||||
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using std::array;
|
||||
using std::pair;
|
||||
using std::tuple;
|
||||
|
||||
struct A { };
|
||||
|
||||
template<template<typename> class pair_like_t>
|
||||
constexpr bool
|
||||
test01()
|
||||
{
|
||||
struct B {
|
||||
int m;
|
||||
constexpr B(A&) : m(0) { }
|
||||
constexpr B(A&&) : m(1) { }
|
||||
constexpr B(const A&) : m(2) { }
|
||||
constexpr B(const A&&) : m(3) { }
|
||||
};
|
||||
|
||||
// template<pair-like UPair>
|
||||
// constexpr explicit(false) pair(UPair&&);
|
||||
|
||||
pair_like_t<A> pair_like;
|
||||
|
||||
[&] {
|
||||
pair<B, B> p2b = pair_like;
|
||||
VERIFY( p2b.first.m == 0 && p2b.second.m == 0 );
|
||||
}();
|
||||
[&] {
|
||||
pair<B, B> p2b = std::move(pair_like);
|
||||
VERIFY( p2b.first.m == 1 && p2b.second.m == 1 );
|
||||
}();
|
||||
[&] {
|
||||
pair<B, B> p2b = std::as_const(pair_like);
|
||||
VERIFY( p2b.first.m == 2 && p2b.second.m == 2 );
|
||||
}();
|
||||
[&] {
|
||||
pair<B, B> p2b = std::move(std::as_const(pair_like));
|
||||
VERIFY( p2b.first.m == 3 && p2b.second.m == 3 );
|
||||
}();
|
||||
|
||||
// Verify dangling checks.
|
||||
static_assert( !std::is_constructible_v<pair<const int&, int>, pair_like_t<long>> );
|
||||
static_assert( !std::is_constructible_v<pair<int, const int&>, pair_like_t<long>> );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<typename> class pair_like_t>
|
||||
constexpr bool
|
||||
test02()
|
||||
{
|
||||
struct B {
|
||||
int m;
|
||||
constexpr explicit B(A&) : m(0) { }
|
||||
constexpr explicit B(A&&) : m(1) { }
|
||||
constexpr explicit B(const A&) : m(2) { }
|
||||
constexpr explicit B(const A&&) : m(3) { }
|
||||
};
|
||||
|
||||
// template<pair-like UPair>
|
||||
// constexpr explicit(true) pair(UPair&&);
|
||||
|
||||
static_assert( !std::is_convertible_v<pair_like_t<A>, pair<B, B>> );
|
||||
|
||||
pair_like_t<A> pair_like;
|
||||
|
||||
[&] {
|
||||
pair<B, B> p2b{pair_like};
|
||||
VERIFY( p2b.first.m == 0 && p2b.second.m == 0 );
|
||||
}();
|
||||
[&] {
|
||||
pair<B, B> p2b{std::move(pair_like)};
|
||||
VERIFY( p2b.first.m == 1 && p2b.second.m == 1 );
|
||||
}();
|
||||
[&] {
|
||||
pair<B, B> p2b{std::as_const(pair_like)};
|
||||
VERIFY( p2b.first.m == 2 && p2b.second.m == 2 );
|
||||
}();
|
||||
[&] {
|
||||
pair<B, B> p2b{std::move(std::as_const(pair_like))};
|
||||
VERIFY( p2b.first.m == 3 && p2b.second.m == 3 );
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<typename> class pair_like_t>
|
||||
constexpr bool
|
||||
test03()
|
||||
{
|
||||
struct B {
|
||||
int m;
|
||||
constexpr B& operator=(A&) { m = 0; return *this; }
|
||||
constexpr B& operator=(A&&) { m = 1; return *this; }
|
||||
constexpr B& operator=(const A&) { m = 2; return *this; }
|
||||
constexpr B& operator=(const A&&) { m = 3; return *this; }
|
||||
};
|
||||
|
||||
// template<pair-like UPair>
|
||||
// constexpr pair& operator=(UPair&&);
|
||||
|
||||
pair_like_t<A> pair_like;
|
||||
|
||||
pair<B, B> p2b;
|
||||
p2b = pair_like;
|
||||
VERIFY( p2b.first.m == 0 && p2b.second.m == 0 );
|
||||
p2b = std::move(pair_like);
|
||||
VERIFY( p2b.first.m == 1 && p2b.second.m == 1 );
|
||||
p2b = std::as_const(pair_like);
|
||||
VERIFY( p2b.first.m == 2 && p2b.second.m == 2 );
|
||||
p2b = std::move(std::as_const(pair_like));
|
||||
VERIFY( p2b.first.m == 3 && p2b.second.m == 3 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<typename> class pair_like_t>
|
||||
constexpr bool
|
||||
test04()
|
||||
{
|
||||
struct B {
|
||||
mutable int m;
|
||||
constexpr const B& operator=(A&) const { m = 0; return *this; }
|
||||
constexpr const B& operator=(A&&) const { m = 1; return *this; }
|
||||
constexpr const B& operator=(const A&) const { m = 2; return *this; }
|
||||
constexpr const B& operator=(const A&&) const { m = 3; return *this; }
|
||||
};
|
||||
|
||||
// template<pair-like UPair>
|
||||
// constexpr const pair& operator=(UPair&&) const;
|
||||
|
||||
pair_like_t<A> pair_like;
|
||||
|
||||
const pair<B, B> p2b;
|
||||
p2b = pair_like;
|
||||
VERIFY( p2b.first.m == 0 && p2b.second.m == 0 );
|
||||
p2b = std::move(pair_like);
|
||||
VERIFY( p2b.first.m == 1 && p2b.second.m == 1 );
|
||||
p2b = std::as_const(pair_like);
|
||||
VERIFY( p2b.first.m == 2 && p2b.second.m == 2 );
|
||||
p2b = std::move(std::as_const(pair_like));
|
||||
VERIFY( p2b.first.m == 3 && p2b.second.m == 3 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
using pair_like_array = array<T, 2>;
|
||||
|
||||
template<typename T>
|
||||
using pair_like_tuple = tuple<T, T>;
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
static_assert( test01<pair_like_array>() );
|
||||
static_assert( test02<pair_like_array>() );
|
||||
static_assert( test03<pair_like_array>() );
|
||||
static_assert( test04<pair_like_array>() );
|
||||
|
||||
static_assert( test01<pair_like_tuple>() );
|
||||
static_assert( test02<pair_like_tuple>() );
|
||||
static_assert( test03<pair_like_tuple>() );
|
||||
static_assert( test04<pair_like_tuple>() );
|
||||
}
|
335
libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc
Normal file
335
libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc
Normal file
|
@ -0,0 +1,335 @@
|
|||
// Verify P2165R4 enhancements to std::tuple.
|
||||
// { dg-do run { target c++23 } }
|
||||
|
||||
#include <array>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
using std::array;
|
||||
using std::pair;
|
||||
using std::tuple;
|
||||
using std::allocator;
|
||||
using std::allocator_arg_t;
|
||||
using std::allocator_arg;
|
||||
|
||||
namespace alloc {
|
||||
struct B01;
|
||||
struct B02;
|
||||
}
|
||||
|
||||
template<> struct std::uses_allocator<alloc::B01, allocator<int>> : std::true_type { };
|
||||
template<> struct std::uses_allocator<alloc::B02, allocator<int>> : std::true_type { };
|
||||
|
||||
struct A { };
|
||||
|
||||
template<template<typename> class tuple_like_t>
|
||||
constexpr bool
|
||||
test01()
|
||||
{
|
||||
struct B {
|
||||
int m;
|
||||
constexpr B(A&) : m(0) { }
|
||||
constexpr B(A&&) : m(1) { }
|
||||
constexpr B(const A&) : m(2) { }
|
||||
constexpr B(const A&&) : m(3) { }
|
||||
};
|
||||
|
||||
// template<tuple-like UTuple>
|
||||
// constexpr explicit(false) tuple(UTuple&&);
|
||||
|
||||
tuple_like_t<A> tuple_like;
|
||||
|
||||
[&] {
|
||||
tuple<B, B, B> t3b = tuple_like;
|
||||
VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b = std::move(tuple_like);
|
||||
VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b = std::as_const(tuple_like);
|
||||
VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b = std::move(std::as_const(tuple_like));
|
||||
VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
|
||||
}();
|
||||
|
||||
// Verify dangling checks.
|
||||
static_assert( !std::is_constructible_v<tuple<const int&, int, int>, tuple_like_t<long>> );
|
||||
static_assert( !std::is_constructible_v<tuple<int, const int&, int>, tuple_like_t<long>> );
|
||||
static_assert( !std::is_constructible_v<tuple<int, int, const int&>, tuple_like_t<long>> );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace alloc
|
||||
{
|
||||
struct B01 {
|
||||
int m;
|
||||
B01(A&);
|
||||
B01(A&&);
|
||||
B01(const A&);
|
||||
B01(const A&&);
|
||||
constexpr B01(allocator_arg_t, allocator<int>, A&) : m(0) { }
|
||||
constexpr B01(allocator_arg_t, allocator<int>, A&&) : m(1) { }
|
||||
constexpr B01(allocator_arg_t, allocator<int>, const A&) : m(2) { }
|
||||
constexpr B01(allocator_arg_t, allocator<int>, const A&&) : m(3) { }
|
||||
};
|
||||
|
||||
template<template<typename> class tuple_like_t>
|
||||
constexpr bool
|
||||
test01()
|
||||
{
|
||||
using B = B01;
|
||||
|
||||
// template<tuple-like UTuple>
|
||||
// constexpr explicit(false) tuple(allocator_arg_t, const Alloc&, UTuple&&);
|
||||
|
||||
tuple_like_t<A> tuple_like;
|
||||
|
||||
[&] {
|
||||
tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, tuple_like};
|
||||
VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, std::move(tuple_like)};
|
||||
VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, std::as_const(tuple_like)};
|
||||
VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b = {allocator_arg, allocator<int>{}, std::move(std::as_const(tuple_like))};
|
||||
VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
|
||||
}();
|
||||
|
||||
// Verify dangling checks.
|
||||
static_assert( !std::is_constructible_v<tuple<const int&, int, int>,
|
||||
allocator_arg_t, allocator<int>,
|
||||
tuple_like_t<long>> );
|
||||
static_assert( !std::is_constructible_v<tuple<int, const int&, int>,
|
||||
allocator_arg_t, allocator<int>,
|
||||
tuple_like_t<long>> );
|
||||
static_assert( !std::is_constructible_v<tuple<int, int, const int&>,
|
||||
allocator_arg_t, allocator<int>,
|
||||
tuple_like_t<long>> );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
template<template<typename> class tuple_like_t>
|
||||
constexpr bool
|
||||
test02()
|
||||
{
|
||||
struct B {
|
||||
int m;
|
||||
constexpr explicit B(A&) : m(0) { }
|
||||
constexpr explicit B(A&&) : m(1) { }
|
||||
constexpr explicit B(const A&) : m(2) { }
|
||||
constexpr explicit B(const A&&) : m(3) { }
|
||||
};
|
||||
|
||||
// template<tuple-like UTuple>
|
||||
// constexpr explicit(true) tuple(UTuple&&);
|
||||
|
||||
static_assert( !std::is_convertible_v<tuple_like_t<A>, tuple<B, B, B>> );
|
||||
|
||||
tuple_like_t<A> tuple_like;
|
||||
|
||||
[&] {
|
||||
tuple<B, B, B> t3b{tuple_like};
|
||||
VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b{std::move(tuple_like)};
|
||||
VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b{std::as_const(tuple_like)};
|
||||
VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b{std::move(std::as_const(tuple_like))};
|
||||
VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace alloc
|
||||
{
|
||||
struct B02 {
|
||||
int m;
|
||||
explicit B02(A&);
|
||||
explicit B02(A&&);
|
||||
explicit B02(const A&);
|
||||
explicit B02(const A&&);
|
||||
explicit constexpr B02(allocator_arg_t, allocator<int>, A&) : m(0) { }
|
||||
explicit constexpr B02(allocator_arg_t, allocator<int>, A&&) : m(1) { }
|
||||
explicit constexpr B02(allocator_arg_t, allocator<int>, const A&) : m(2) { }
|
||||
explicit constexpr B02(allocator_arg_t, allocator<int>, const A&&) : m(3) { }
|
||||
};
|
||||
|
||||
template<template<typename> class tuple_like_t>
|
||||
constexpr bool
|
||||
test02()
|
||||
{
|
||||
using B = B02;
|
||||
|
||||
// template<tuple-like UTuple>
|
||||
// constexpr explicit(true) tuple(allocator_arg_t, const Alloc&, UTuple&&);
|
||||
|
||||
static_assert( !std::is_convertible_v<tuple_like_t<A>, tuple<B, B, B>> );
|
||||
|
||||
tuple_like_t<A> tuple_like;
|
||||
|
||||
[&] {
|
||||
tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, tuple_like};
|
||||
VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, std::move(tuple_like)};
|
||||
VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, std::as_const(tuple_like)};
|
||||
VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
|
||||
}();
|
||||
[&] {
|
||||
tuple<B, B, B> t3b{allocator_arg, allocator<int>{}, std::move(std::as_const(tuple_like))};
|
||||
VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
|
||||
}();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<template<typename> class tuple_like_t>
|
||||
constexpr bool
|
||||
test03()
|
||||
{
|
||||
struct B {
|
||||
int m;
|
||||
constexpr B& operator=(A&) { m = 0; return *this; }
|
||||
constexpr B& operator=(A&&) { m = 1; return *this; }
|
||||
constexpr B& operator=(const A&) { m = 2; return *this; }
|
||||
constexpr B& operator=(const A&&) { m = 3; return *this; }
|
||||
};
|
||||
|
||||
// template<tuple-like UTuple>
|
||||
// constexpr tuple& operator=(UTuple&&);
|
||||
|
||||
tuple_like_t<A> tuple_like;
|
||||
|
||||
tuple<B, B, B> t3b;
|
||||
t3b = tuple_like;
|
||||
VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
|
||||
t3b = std::move(tuple_like);
|
||||
VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
|
||||
t3b = std::as_const(tuple_like);
|
||||
VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
|
||||
t3b = std::move(std::as_const(tuple_like));
|
||||
VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<typename> class tuple_like_t>
|
||||
constexpr bool
|
||||
test04()
|
||||
{
|
||||
struct B {
|
||||
mutable int m;
|
||||
constexpr const B& operator=(A&) const { m = 0; return *this; }
|
||||
constexpr const B& operator=(A&&) const { m = 1; return *this; }
|
||||
constexpr const B& operator=(const A&) const { m = 2; return *this; }
|
||||
constexpr const B& operator=(const A&&) const { m = 3; return *this; }
|
||||
};
|
||||
|
||||
// template<tuple-like UTuple>
|
||||
// constexpr const tuple& operator=(UTuple&&) const;
|
||||
|
||||
tuple_like_t<A> tuple_like;
|
||||
|
||||
const tuple<B, B, B> t3b;
|
||||
t3b = tuple_like;
|
||||
VERIFY( std::get<0>(t3b).m == 0 && std::get<1>(t3b).m == 0 && std::get<2>(t3b).m == 0 );
|
||||
t3b = std::move(tuple_like);
|
||||
VERIFY( std::get<0>(t3b).m == 1 && std::get<1>(t3b).m == 1 && std::get<2>(t3b).m == 1 );
|
||||
t3b = std::as_const(tuple_like);
|
||||
VERIFY( std::get<0>(t3b).m == 2 && std::get<1>(t3b).m == 2 && std::get<2>(t3b).m == 2 );
|
||||
t3b = std::move(std::as_const(tuple_like));
|
||||
VERIFY( std::get<0>(t3b).m == 3 && std::get<1>(t3b).m == 3 && std::get<2>(t3b).m == 3 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<template<typename> class tuple_like_t>
|
||||
constexpr bool
|
||||
test05()
|
||||
{
|
||||
// template<tuple-like UTuple>
|
||||
// constexpr bool operator==(const tuple&, const UTuple&);
|
||||
|
||||
static_assert( tuple{1, 2, 3} == tuple_like_t{1, 2, 3} );
|
||||
static_assert( tuple{1, 2, 4} != tuple_like_t{1, 2, 3} );
|
||||
static_assert( tuple_like_t{1, 2, 3} == tuple{1, 2, 3} );
|
||||
static_assert( tuple_like_t{1, 2, 3} != tuple{1, 2, 4} );
|
||||
|
||||
// template<tuple-like UTuple>
|
||||
// constexpr bool operator<=>const tuple&, const UTuple&);
|
||||
|
||||
static_assert( (tuple{1, 2, 3} <=> tuple_like_t{1, 2, 3}) == std::strong_ordering::equal );
|
||||
static_assert( (tuple{1, 2, 4} <=> tuple_like_t{1, 2, 3}) == std::strong_ordering::greater );
|
||||
static_assert( (tuple_like_t{1, 2, 3} <=> tuple{1, 2, 3}) == std::strong_ordering::equal );
|
||||
static_assert( (tuple_like_t{1, 2, 3} <=> tuple{1, 2, 4}) == std::strong_ordering::less );
|
||||
|
||||
static_assert( tuple{1, 2, 4} > tuple_like_t{1, 2, 3} );
|
||||
static_assert( tuple_like_t{1, 2, 3} < tuple{1, 2, 4} );
|
||||
|
||||
// template<tuple-like TTuple, tuple-like UTuple, ...>
|
||||
// struct basic_common_reference<TTuple, UTuple, ...>;
|
||||
|
||||
static_assert( std::same_as<std::common_reference_t<tuple_like_t<int>,
|
||||
tuple<int, long, int>>,
|
||||
tuple<int, long, int>> );
|
||||
|
||||
static_assert( std::same_as<std::common_reference_t<tuple<int, long, int>,
|
||||
tuple_like_t<int>>,
|
||||
tuple<int, long, int>> );
|
||||
|
||||
// template<tuple-like TTuple, tuple-like UTuple>
|
||||
// struct common_type<TTuple, UTuple>;
|
||||
|
||||
static_assert( std::same_as<std::common_type_t<tuple_like_t<const int&>,
|
||||
tuple<int, long, int>>,
|
||||
tuple<int, long, int>> );
|
||||
|
||||
static_assert( std::same_as<std::common_type_t<tuple<int, long, int>,
|
||||
tuple_like_t<const int&>>,
|
||||
tuple<int, long, int>> );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
using tuple_like_array = array<T, 3>;
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
static_assert( test01<tuple_like_array>() );
|
||||
static_assert( alloc::test01<tuple_like_array>() );
|
||||
static_assert( test02<tuple_like_array>() );
|
||||
static_assert( alloc::test02<tuple_like_array>() );
|
||||
static_assert( test03<tuple_like_array>() );
|
||||
static_assert( test04<tuple_like_array>() );
|
||||
static_assert( test05<tuple_like_array>() );
|
||||
}
|
|
@ -41,8 +41,8 @@ test01()
|
|||
VERIFY( i2 == z2.end() );
|
||||
VERIFY( ranges::size(z2) == 2 );
|
||||
VERIFY( ranges::size(std::as_const(z2)) == 2 );
|
||||
VERIFY( z2[0].first == 1 && z2[0].second == 3 );
|
||||
VERIFY( z2[1].first == 2 && z2[1].second == 4 );
|
||||
VERIFY( std::get<0>(z2[0]) == 1 && std::get<1>(z2[0]) == 3 );
|
||||
VERIFY( std::get<0>(z2[1]) == 2 && std::get<1>(z2[1]) == 4 );
|
||||
for (const auto [x, y] : z2)
|
||||
{
|
||||
VERIFY( y - x == 2 );
|
||||
|
@ -124,6 +124,18 @@ test04()
|
|||
return true;
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
test05()
|
||||
{
|
||||
// PR libstdc++/109203
|
||||
int x[] = {1, 1, 2};
|
||||
int y[] = {2, 1, 3};
|
||||
auto r = views::zip(x, y);
|
||||
ranges::sort(r);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
@ -131,4 +143,5 @@ main()
|
|||
static_assert(test02());
|
||||
static_assert(test03());
|
||||
static_assert(test04());
|
||||
static_assert(test05());
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue