diff options
author | Patrick Palka <ppalka@redhat.com> | 2024-02-01 14:59:46 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2024-02-01 14:59:46 -0500 |
commit | 65b4cba9d6a9ffe9b4d4bdff90727a7064cc0e3b (patch) | |
tree | 294dd6fdadc946c51eafcf6b30b989034a637edf /libstdc++-v3/testsuite | |
parent | 87d162383ed68c55311a55784f6b40e979945c00 (diff) | |
download | gcc-65b4cba9d6a9ffe9b4d4bdff90727a7064cc0e3b.zip gcc-65b4cba9d6a9ffe9b4d4bdff90727a7064cc0e3b.tar.gz gcc-65b4cba9d6a9ffe9b4d4bdff90727a7064cc0e3b.tar.bz2 |
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>
Diffstat (limited to 'libstdc++-v3/testsuite')
-rw-r--r-- | libstdc++-v3/testsuite/20_util/pair/p2165r4.cc | 173 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc | 335 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/std/ranges/zip/1.cc | 17 |
3 files changed, 523 insertions, 2 deletions
diff --git a/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc b/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc new file mode 100644 index 0000000..ef06df1 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/p2165r4.cc @@ -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>() ); +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc b/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc new file mode 100644 index 0000000..e2437c4 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/p2165r4.cc @@ -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>() ); +} diff --git a/libstdc++-v3/testsuite/std/ranges/zip/1.cc b/libstdc++-v3/testsuite/std/ranges/zip/1.cc index b7717ae..ea4274d 100644 --- a/libstdc++-v3/testsuite/std/ranges/zip/1.cc +++ b/libstdc++-v3/testsuite/std/ranges/zip/1.cc @@ -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()); } |