On Fri, Apr 18, 2025 at 1:37 PM Luc Grosheintz <luc.groshei...@gmail.com> wrote:
> A prior commit added std::extents, this commit adds the tests. The bulk > is focussed on testing the constructors. These are split into three > groups: > > 1. the ctor from other extents and the copy ctor, > 2. the ctor from a pack of integer-like objects, > 3. the ctor from shapes, i.e. span and array. > > For each group check that the ctor: > * produces an object with the expected values for extent, > * is implicit if and only if required, > * is constexpr, > * doesn't change the rank of the extent. > > libstdc++-v3/ChangeLog: > > * testsuite/23_containers/mdspan/extents/class_mandates_neg.cc: > New test. > * testsuite/23_containers/mdspan/extents/ctor_copy.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_ints.cc: New test. > * testsuite/23_containers/mdspan/extents/ctor_shape.cc: New test. > * testsuite/23_containers/mdspan/extents/custom_integer.cc: New > test. > * testsuite/23_containers/mdspan/extents/misc.cc: New test. > > Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> > --- > LGTM > .../mdspan/extents/class_mandates_neg.cc | 8 + > .../23_containers/mdspan/extents/ctor_copy.cc | 82 +++++++ > .../23_containers/mdspan/extents/ctor_ints.cc | 62 +++++ > .../mdspan/extents/ctor_shape.cc | 160 +++++++++++++ > .../mdspan/extents/custom_integer.cc | 87 +++++++ > .../23_containers/mdspan/extents/misc.cc | 223 ++++++++++++++++++ > 6 files changed, 622 insertions(+) > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc > create mode 100644 > libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc > > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc > new file mode 100644 > index 00000000000..bbb3e0ad144 > --- /dev/null > +++ > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/class_mandates_neg.cc > @@ -0,0 +1,8 @@ > +// { dg-do compile { target c++23 } } > +#include<mdspan> > + > +std::extents<std::int32_t, size_t(1) << 32> e1; // { dg-error "from here" > } > +std::extents<double, 1> e2; // { dg-error "from here" > } > +// { dg-prune-output "dynamic or representable as _IndexType" } > +// { dg-prune-output "must be integral" } > +// { dg-prune-output "invalid use of incomplete type" } > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc > new file mode 100644 > index 00000000000..a7b3a169301 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_copy.cc > @@ -0,0 +1,82 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +// Test the copy ctor and the ctor from other extents. > + > +constexpr auto dyn = std::dynamic_extent; > + > +// Not constructible > +static_assert(!std::is_constructible_v<std::extents<int>, > + std::extents<int, 1>>); > + > +static_assert(!std::is_constructible_v<std::extents<int, 1, 1>, > + std::extents<int, 1>>); > + > +static_assert(!std::is_constructible_v<std::extents<int, dyn>, > + std::extents<int, dyn, dyn>>); > + > +static_assert(!std::is_constructible_v<std::extents<int, 2, 2>, > + std::extents<int, 1, 2>>); > + > +// Nothrow constructible > +static_assert(std::is_nothrow_constructible_v<std::extents<int, 1>, > + std::extents<unsigned int, > dyn>>); > +static_assert(std::is_nothrow_constructible_v<std::extents<unsigned int, > dyn>, > + std::extents<int, 1>>); > + > +// Implicit conversion > +static_assert(!std::is_convertible_v<std::extents<unsigned int>, > + std::extents<int>>); > +static_assert(std::is_convertible_v<std::extents<int>, > + std::extents<unsigned int>>); > + > +static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>, > + std::extents<int, 1>>); > +static_assert(std::is_convertible_v<std::extents<int, 1>, > + std::extents<unsigned int, 1>>); > + > +static_assert(!std::is_convertible_v<std::extents<int, dyn>, > + std::extents<int, 1>>); > +static_assert(std::is_convertible_v<std::extents<int, 1>, > + std::extents<int, dyn>>); > + > +static_assert(!std::is_convertible_v<std::extents<unsigned int, 1>, > + std::extents<int, dyn>>); > +static_assert(std::is_convertible_v<std::extents<int, 1>, > + std::extents<unsigned int, dyn>>); > + > +template<typename T, size_t... Extents, typename Other> > + constexpr void > + test_ctor(const Other& other) > + { > + auto e = std::extents<T, Extents...>(other); > + VERIFY(e == other); > + } > + > +constexpr int > +test_all() > +{ > + auto e0 = std::extents<int>(); > + test_ctor<int>(e0); > + > + auto e1 = std::extents<int, 1, 2, 3>(); > + test_ctor<int, 1, 2, 3>(e1); > + test_ctor<int, 1, dyn, 3>(e1); > + test_ctor<unsigned int, 1, dyn, 3>(e1); > + > + auto e2 = std::extents<unsigned int, 1, dyn, 3>{1, 2, 3}; > + test_ctor<int, 1, 2, 3>(e2); > + test_ctor<int, 1, dyn, 3>(e2); > + test_ctor<int, 1, dyn, dyn>(e2); > + return true; > +} > + > +int > +main() > +{ > + test_all(); > + static_assert(test_all()); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc > new file mode 100644 > index 00000000000..53cf14d9bc5 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc > @@ -0,0 +1,62 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr auto dyn = std::dynamic_extent; > + > +class A {}; > + > +// Not constructible if the number of integer-like arguments isn't either > +// rank() or rank_dynamic(). > +static_assert(!std::is_constructible_v<std::extents<int>, int>); > +static_assert(!std::is_constructible_v<std::extents<int, dyn, dyn>, int>); > +static_assert(!std::is_constructible_v<std::extents<int, 1, dyn, 3>, int, > int>); > + > +// Not constructible from non integer-like objects. > +static_assert(!std::is_constructible_v<std::extents<int, 1>, int, A>); > + > +// No implicit conversion from integer-like objects. > +template<typename Extent, typename... OExtents> > + constexpr bool > + is_explicit() > + { > + return std::is_nothrow_constructible_v<Extent, OExtents...> > + && !std::is_convertible_v<Extent, OExtents...>; > + } > + > +static_assert(is_explicit<std::extents<int, 1>, int>()); > +static_assert(is_explicit<std::extents<int, 1>, unsigned int>()); > +static_assert(is_explicit<std::extents<unsigned int, 1>, int>()); > + > +constexpr bool > +test_all() > +{ > + auto expected = std::extents<int, 1, 2, 3>(1, 2, 3); > + > + // From all extents. > + VERIFY((std::extents<int, 1, 2, 3>(1, 2, 3)) == expected); > + VERIFY((std::extents<int, dyn, 2, 3>(1, 2, 3)) == expected); > + VERIFY((std::extents<int, dyn, 2, dyn>(1, 2, 3)) == expected); > + > + VERIFY((std::extents<int, 1, 2, 3>{1, 2, 3}) == expected); > + VERIFY((std::extents<int, dyn, 2, 3>{1, 2, 3}) == expected); > + VERIFY((std::extents<int, dyn, 2, dyn>{1, 2, 3}) == expected); > + > + // From only dynamic extents. > + VERIFY((std::extents<int, dyn, 2, 3>(1)) == expected); > + VERIFY((std::extents<int, dyn, 2, dyn>(1, 3)) == expected); > + > + VERIFY((std::extents<int, dyn, 2, 3>{1}) == expected); > + VERIFY((std::extents<int, dyn, 2, dyn>{1, 3}) == expected); > + > + return true; > +} > + > +int > +main() > +{ > + test_all(); > + static_assert(test_all); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc > new file mode 100644 > index 00000000000..72e06df42ce > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc > @@ -0,0 +1,160 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr auto dyn = std::dynamic_extent; > + > +template<typename Extent, typename T, size_t N> > + constexpr bool > + constructible() > + { > + return std::is_nothrow_constructible_v<Extent, std::array<T, N>> > + && std::is_nothrow_constructible_v<Extent, std::span<T, N>>; > + } > + > +template<typename Extent, typename T, size_t N> > + constexpr bool > + not_constructible() > + { > + return !std::is_constructible_v<Extent, std::array<T, N>> > + && !std::is_constructible_v<Extent, std::span<T, N>>; > + } > + > +template<typename Extent, typename T, size_t N> > + constexpr bool > + convertible() > + { > + return std::is_convertible_v<std::array<T, N>, Extent> > + && std::is_convertible_v<std::span<T, N>, Extent>; > + } > + > +template<typename Extent, typename T, size_t N> > + constexpr bool > + not_convertible() > + { > + return !std::is_convertible_v<std::array<T, N>, Extent> > + && !std::is_convertible_v<std::span<T, N>, Extent>; > + } > + > +static_assert(constructible<std::extents<int, 1, 2>, int, 2>); > +static_assert(not_constructible<std::extents<int, 1, 2>, int, 1>); > + > +static_assert(constructible<std::extents<int>, int, 0>()); > +static_assert(convertible<std::extents<int>, int, 0>()); > +static_assert(convertible<std::extents<unsigned int>, int, 0>()); > +static_assert(convertible<std::extents<int>, unsigned int, 0>()); > + > +static_assert(constructible<std::extents<int, 1, dyn>, int, 1>()); > +static_assert(convertible<std::extents<int, 1, dyn>, int, 1>()); > +static_assert(convertible<std::extents<unsigned int, 1, dyn>, int, 1>()); > +static_assert(convertible<std::extents<int, 1, dyn>, unsigned int, 1>()); > + > +static_assert(constructible<std::extents<int, 1, dyn>, int, 2>()); > +static_assert(not_convertible<std::extents<int, 1, dyn>, int, 2>()); > +static_assert(not_convertible<std::extents<unsigned int, 1, dyn>, int, > 2>()); > +static_assert(not_convertible<std::extents<int, 1, dyn>, unsigned int, > 2>()); > + > +// Non-integer, but convertible. > +static_assert(constructible<std::extents<int, dyn>, double, 1>()); > +static_assert(convertible<std::extents<int, dyn>, double, 1>()); > + > +namespace all_extents > +{ > + template<typename Shape> > + constexpr void > + test_ctor(Shape shape) > + { > + auto expected = std::extents<int, 1, 2, 3>(); > + VERIFY((std::extents<int, 1, dyn, 3>(shape)) == expected); > + VERIFY((std::extents<int, dyn, dyn, dyn>(shape)) == expected); > + VERIFY((std::extents<int, 1, 2, 3>(shape)) == expected); > + } > + > + constexpr void > + test_common_shapes() > + { > + auto array = std::array<int, 3>{1, 2, 3}; > + auto span_const = std::span<const int, 3>(array); > + auto span = std::span<int, 3>(array); > + > + test_ctor(array); > + test_ctor(span); > + test_ctor(span_const); > + } > + > + constexpr void > + test_empty_shapes() > + { > + auto shape = std::array<int, 0>(); > + auto span = std::span<int, 0>(shape); > + > + auto expected = std::extents<int>(); > + VERIFY((std::extents<int>(shape)) == expected); > + VERIFY((std::extents<int>(span)) == expected); > + } > + > + constexpr bool > + test_all() > + { > + test_common_shapes(); > + test_empty_shapes(); > + return true; > + } > +} > + > +namespace only_dynamic_extents > +{ > + template<typename Extents, typename Shape> > + constexpr void > + test_ctor(const Shape& shape) > + { > + Extents e = shape; > + > + VERIFY(e.rank_dynamic() == shape.size()); > + > + size_t di = 0; > + for(size_t i = 0; i < e.rank(); ++i) > + if(e.static_extent(i) == dyn) > + VERIFY(e.extent(i) == shape[di++]); > + } > + > + template<typename Extents, typename T, size_t N> > + constexpr void > + test_all_shape_types(std::array<T, N> shape) > + { > + test_ctor<Extents>(shape); > + test_ctor<Extents>(std::span<T, N>(shape)); > + test_ctor<Extents>(std::span<const T, N>(shape)); > + } > + > + constexpr void > + test_common_shapes() > + { > + auto s = std::array<int, 0>{}; > + auto s2 = std::array<int, 1>{2}; > + auto s123 = std::array<int, 3>{1, 2, 3}; > + > + test_all_shape_types<std::extents<int, 1, dyn, 3>>(s2); > + test_all_shape_types<std::extents<int, dyn, dyn, dyn>>(s123); > + test_all_shape_types<std::extents<int, 1, 2, 3>>(s); > + } > + > + constexpr bool > + test_all() > + { > + test_common_shapes(); > + return true; > + } > +} > + > +int > +main() > +{ > + all_extents::test_all(); > + static_assert(all_extents::test_all()); > + > + only_dynamic_extents::test_all(); > + static_assert(only_dynamic_extents::test_all()); > + return 0; > +} > diff --git > a/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc > new file mode 100644 > index 00000000000..2907ad12ae7 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/custom_integer.cc > @@ -0,0 +1,87 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +// Test construction from a custom integer-like object, that has > +// no copy/move ctor or copy/move assignment operator. > + > +constexpr size_t dyn = std::dynamic_extent; > + > +class IntLike > +{ > +public: > + explicit > + IntLike(int i) > + : _M_i(i) > + { } > + > + IntLike() = delete; > + IntLike(const IntLike&) = delete; > + IntLike(IntLike&&) = delete; > + > + const IntLike& > + operator=(const IntLike&) = delete; > + > + const IntLike& > + operator=(IntLike&&) = delete; > + > + constexpr > + operator int() const noexcept > + { return _M_i; } > + > +private: > + int _M_i; > +}; > + > +static_assert(std::is_convertible_v<IntLike, int>); > +static_assert(std::is_nothrow_constructible_v<int, IntLike>); > + > +void > +test_shape(const auto& s2, const auto& s23) > +{ > + std::extents<int, 2, 3> expected; > + > + std::extents<int, 2, 3> e1(s23); > + VERIFY(e1 == expected); > + > + std::extents<int, dyn, 3> e2(s2); > + VERIFY(e2 == expected); > + > + std::extents<int, dyn, 3> e3(s23); > + VERIFY(e3 == expected); > + > + std::extents<int, dyn, dyn> e4(s23); > + VERIFY(e4 == expected); > +} > + > +void > +test_pack() > +{ > + std::extents<int, 2, 3> expected; > + > + std::extents<int, dyn, 3> e1(IntLike(2)); > + VERIFY(e1 == expected); > + > + std::extents<int, dyn, 3> e2(IntLike(2), IntLike(3)); > + VERIFY(e2 == expected); > + > + std::extents<int, dyn, dyn> e3(IntLike(2), IntLike(3)); > + VERIFY(e3 == expected); > +} > + > +int > +main() > +{ > + auto a2 = std::array<IntLike, 1>{IntLike(2)}; > + auto s2 = std::span<IntLike, 1>(a2); > + > + auto a23 = std::array<IntLike, 2>{IntLike(2), IntLike(3)}; > + auto s23 = std::span<IntLike, 2>(a23); > + > + test_shape(a2, a23); > + test_shape(s2, s23); > + test_pack(); > + > + return 0; > +} > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc > b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc > new file mode 100644 > index 00000000000..98c47ce7892 > --- /dev/null > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc > @@ -0,0 +1,223 @@ > +// { dg-do run { target c++23 } } > +#include <mdspan> > + > +#include <testsuite_hooks.h> > + > +constexpr size_t dyn = std::dynamic_extent; > + > +// Check class traits. > +static_assert(std::regular<std::extents<int>>); > +static_assert(std::regular<std::extents<int, 1>>); > +static_assert(std::regular<std::extents<int, dyn>>); > + > +static_assert(std::is_trivially_copyable_v<std::extents<int>>); > +static_assert(std::is_trivially_copyable_v<std::extents<int, 1>>); > +static_assert(std::is_trivially_copyable_v<std::extents<int, dyn>>); > + > +// Check member typedefs. > +static_assert(std::is_same_v<std::extents<int, 1, 2>::rank_type, size_t>); > + > +static_assert(std::is_unsigned_v<std::extents<int, 2>::size_type>); > +static_assert(std::is_unsigned_v<std::extents<unsigned int, > 2>::size_type>); > + > +static_assert(std::is_same_v<std::extents<char, 2>::index_type, char>); > +static_assert(std::is_same_v<std::extents<int, 2>::index_type, int>); > +static_assert(std::is_same_v<std::extents<unsigned int, 2>::index_type, > + unsigned int>); > + > +// Check `rank`. > +static_assert(std::extents<int, 1>::rank() == 1); > +static_assert(std::extents<int, dyn>::rank() == 1); > +static_assert(std::extents<int, 2, dyn>::rank() == 2); > + > +// Check `rank_dynamic`. > +static_assert(std::extents<int, 1>::rank_dynamic() == 0); > +static_assert(std::extents<int, dyn>::rank_dynamic() == 1); > +static_assert(std::extents<int, 2, dyn>::rank_dynamic() == 1); > +static_assert(std::extents<int, dyn, dyn>::rank_dynamic() == 2); > + > +template<typename T, size_t... Extents> > + constexpr bool > + check_rank_return_types() > + { > + auto e = std::extents<T, Extents...>(); > + return std::is_same_v<decltype(e.rank()), size_t> > + && std::is_same_v<decltype(e.rank_dynamic()), size_t>; > + } > + > +static_assert(check_rank_return_types<int, 1>()); > + > +// Check that the static extents don't take up space. > +static_assert(sizeof(std::extents<int, 1, dyn>) == sizeof(int)); > +static_assert(sizeof(std::extents<char, 1, dyn>) == sizeof(char)); > + > +template<typename Extents> > +class Container > +{ > + int dummy; > + [[no_unique_address]] std::extents<size_t> b0; > +}; > + > +static_assert(sizeof(Container<std::extents<char, 1, 2>>) == sizeof(int)); > +static_assert(sizeof(Container<std::extents<size_t, 1, 2>>) == > sizeof(int)); > + > +// operator= > +static_assert(std::is_nothrow_assignable_v<std::extents<int, dyn, 2>, > + std::extents<int, 1, 2>>); > + > +constexpr bool > +test_assign() > +{ > + auto e1 = std::extents<int, 1, 2>(); > + auto e2 = std::extents<int, 1, 2>(); > + > + e2 = e1; > + VERIFY(e2 == e1); > + > + auto e5 = std::extents<int, 1, dyn>(); > + e5 = e1; > + VERIFY(e5 == e1); > + > + auto e3 = std::extents<int, dyn, dyn>(1, 2); > + auto e4 = std::extents<int, dyn, dyn>(3, 4); > + e3 = e4; > + VERIFY(e3 == e4); > + return true; > +} > + > +// Deduction guide > +template<size_t Rank, typename... Extents> > +constexpr void > +test_deduction(Extents... exts) > +{ > + std::array<size_t, sizeof...(exts)> shape{static_cast<size_t>(exts)...}; > + std::dextents<size_t, Rank> expected(shape); > + std::extents e(exts...); > + static_assert(std::is_same_v<decltype(e), std::dextents<size_t, Rank>>); > + VERIFY(e == expected); > +} > + > +constexpr bool > +test_deduction_all() > +{ > + test_deduction<0>(); > + test_deduction<1>(1); > + test_deduction<2>(1.0, 2.0f); > + test_deduction<3>(int(1), char(2), size_t(3)); > + return true; > +} > + > +class A {}; > + > +template<typename... Extents> > + concept deducible = requires > + { > + { std::extents(Extents{}...) } > + -> std::convertible_to<std::dextents<size_t, sizeof...(Extents)>>; > + }; > + > +static_assert(deducible<int>); > +static_assert(!deducible<A, A>); > + > +// dextents > +static_assert(std::is_same_v<std::dextents<int, 0>, std::extents<int>>); > +static_assert(std::is_same_v<std::dextents<int, 1>, std::extents<int, > dyn>>); > +static_assert(std::is_same_v<std::dextents<int, 5>, > + std::extents<int, dyn, dyn, dyn, dyn, dyn>>); > + > +static_assert(std::dextents<int, 5>::rank() == 5); > +static_assert(std::dextents<int, 5>::rank_dynamic() == 5); > +static_assert(std::is_same_v<typename std::dextents<int, 5>::index_type, > int>); > + > +// static_extent > +static_assert(std::extents<int, 1, 2>::static_extent(0) == 1); > +static_assert(std::extents<int, 1, 2>::static_extent(1) == 2); > + > +static_assert(std::extents<int, 1, dyn>::static_extent(0) == 1); > +static_assert(std::extents<int, 1, dyn>::static_extent(1) == dyn); > + > +static_assert(std::extents<int, dyn, dyn>::static_extent(0) == dyn); > +static_assert(std::extents<int, dyn, dyn>::static_extent(1) == dyn); > + > +// extent > +template<typename Extent> > + constexpr void > + test_extent(const Extent& e, const std::array<size_t, Extent::rank()>& > shape) > + { > + for(size_t i = 0; i < e.rank(); ++i) > + VERIFY(e.extent(i) == shape[i]); > + } > + > +constexpr bool > +test_extent_all() > +{ > + test_extent(std::extents<int, 1, 2>{}, {1, 2}); > + test_extent(std::extents<int, 1, dyn>{2}, {1, 2}); > + test_extent(std::extents<int, dyn, dyn>{1, 2}, {1, 2}); > + return true; > +} > + > +// operator== > +template<typename Lhs, typename Rhs> > + constexpr void > + test_ops_eq(const Lhs& lhs, const Rhs& rhs, bool expected) > + { > + VERIFY((lhs == rhs) == expected); > + VERIFY((lhs != rhs) == !expected); > + } > + > +constexpr void > +test_op_eq_rank_zero() > +{ > + auto e1 = std::extents<int>(); > + auto e2 = std::extents<int>(); > + auto e3 = std::extents<unsigned int>(); > + > + test_ops_eq(e1, e2, true); > + test_ops_eq(e1, e3, true); > +} > + > +constexpr void > +test_op_eq_common() > +{ > + auto e1 = std::extents<int, 1, 2, 3>(); > + auto e2 = std::extents<int, 1, 2, 3>(); > + auto e3 = std::extents<int, 1, dyn, 3>(2); > + auto e4 = std::extents<int, 1, dyn, 3>(3); > + > + auto e5 = std::extents<int, 1>(); > + auto e6 = std::extents<int, 1, 3, 3>(); > + > + test_ops_eq(e1, e2, true); > + test_ops_eq(e1, e3, true); > + test_ops_eq(e1, e4, false); > + > + test_ops_eq(e1, e5, false); > + test_ops_eq(e1, e6, false); > + test_ops_eq(e3, e6, false); > +} > + > +constexpr bool > +test_op_eq_all() > +{ > + test_op_eq_rank_zero(); > + test_op_eq_common(); > + return true; > +} > + > +int > +main() > +{ > + test_assign(); > + static_assert(test_assign()); > + > + test_deduction_all(); > + static_assert(test_deduction_all()); > + > + test_extent_all(); > + static_assert(test_extent_all()); > + > + test_op_eq_all(); > + static_assert(test_op_eq_all()); > + return 0; > +} > -- > 2.49.0 > >