This was merged. Thanks for working on it. However, the constant_wrapper paper accepted in Sofia, modifies the concept: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2781r8.html
On Tue, Jul 8, 2025 at 1:01 PM Tomasz Kaminski <tkami...@redhat.com> wrote: > Maybe adding a negative test for the error when converting negative values > would be valuable then. > I think we can add it as separate commit later, I will try to get > everything merged today, > > On Tue, Jul 8, 2025 at 12:56 PM Jonathan Wakely <jwak...@redhat.com> > wrote: > >> On Tue, 8 Jul 2025 at 11:46, Tomasz Kaminski <tkami...@redhat.com> wrote: >> > >> > >> > >> > On Tue, Jul 8, 2025 at 12:08 PM Jonathan Wakely <jwak...@redhat.com> >> wrote: >> >> >> >> On Tue, 8 Jul 2025 at 10:54, Luc Grosheintz <luc.groshei...@gmail.com> >> wrote: >> >> > >> >> > This implements P3029R1. In P3029R1, the CTAD for span is refined to >> >> > permit deducing the extent of the span from an integral constant, >> e.g. >> >> > >> >> > span((T*) ptr, integral_constant<size_t, 5>{}); >> >> > >> >> > is deduced as span<T, 5>. Similarly, in >> >> > >> >> > auto exts = extents(integral_constant<int, 2>); >> >> > auto md = mdspan((T*) ptr, integral_constant<int, 2>); >> >> > >> >> > exts and md have types extents<size_t, 2> and mdspan<double, >> >> > extents<size_t, 2>>, respectively. >> >> > >> >> > PR libstdc++/120914 >> >> > >> >> > libstdc++-v3/ChangeLog: >> >> > >> >> > * include/std/span (span): Update CTAD to enable >> >> > integral constants [P3029R1]. >> >> > * include/std/mdspan (extents): ditto. >> >> > (mdspan): ditto. >> >> > * testsuite/23_containers/span/deduction.cc: Test deduction >> >> > guide. >> >> > * testsuite/23_containers/mdspan/extents/misc.cc: ditto. >> >> > * testsuite/23_containers/mdspan/mdspan.cc: ditto. >> >> > >> >> > Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com> >> >> > --- >> >> > libstdc++-v3/include/std/mdspan | 8 ++---- >> >> > libstdc++-v3/include/std/span | 20 ++++++++++++++- >> >> > .../23_containers/mdspan/extents/misc.cc | 20 +++++++++++++++ >> >> > .../testsuite/23_containers/mdspan/mdspan.cc | 25 >> +++++++++++++++++++ >> >> > .../testsuite/23_containers/span/deduction.cc | 3 +++ >> >> > 5 files changed, 69 insertions(+), 7 deletions(-) >> >> > >> >> > diff --git a/libstdc++-v3/include/std/mdspan >> b/libstdc++-v3/include/std/mdspan >> >> > index 0fd78570b3e..152dcb3e92a 100644 >> >> > --- a/libstdc++-v3/include/std/mdspan >> >> > +++ b/libstdc++-v3/include/std/mdspan >> >> > @@ -406,10 +406,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> >> > template<typename _IndexType, size_t... _Counts> >> >> > auto __build_dextents_type(integer_sequence<size_t, >> _Counts...>) >> >> > -> extents<_IndexType, ((void) _Counts, dynamic_extent)...>; >> >> > - >> >> > - template<typename _Tp> >> >> > - consteval size_t >> >> > - __dynamic_extent() { return dynamic_extent; } >> >> > } >> >> > >> >> > template<typename _IndexType, size_t _Rank> >> >> > @@ -419,7 +415,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> >> > template<typename... _Integrals> >> >> > requires (is_convertible_v<_Integrals, size_t> && ...) >> >> > explicit extents(_Integrals...) -> >> >> > - extents<size_t, __mdspan::__dynamic_extent<_Integrals>()...>; >> >> > + extents<size_t, __detail::__maybe_static_ext<_Integrals>...>; >> >> > >> >> > struct layout_left >> >> > { >> >> > @@ -1316,7 +1312,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> >> > && (sizeof...(_Integrals) > 0) >> >> > explicit mdspan(_ElementType*, _Integrals...) >> >> > -> mdspan<_ElementType, >> >> > - extents<size_t, >> __mdspan::__dynamic_extent<_Integrals>()...>>; >> >> > + extents<size_t, >> __detail::__maybe_static_ext<_Integrals>...>>; >> >> > >> >> > template<typename _ElementType, typename _OIndexType, size_t _Nm> >> >> > mdspan(_ElementType*, span<_OIndexType, _Nm>) >> >> > diff --git a/libstdc++-v3/include/std/span >> b/libstdc++-v3/include/std/span >> >> > index 49ab9109d83..5629a71b9bd 100644 >> >> > --- a/libstdc++-v3/include/std/span >> >> > +++ b/libstdc++-v3/include/std/span >> >> > @@ -476,6 +476,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> >> > }; >> >> > >> >> > // deduction guides >> >> > + namespace __detail >> >> > + { >> >> > + template<typename _Tp> >> >> > + concept __integral_constant_like = >> is_integral_v<decltype(_Tp::value)> >> >> > + && !is_same_v<bool, remove_const_t<decltype(_Tp::value)>> >> >> > + && convertible_to<_Tp, decltype(_Tp::value)> >> >> > + && equality_comparable_with<_Tp, decltype(_Tp::value)> >> >> > + && bool_constant<_Tp() == _Tp::value>::value >> >> > + && bool_constant<static_cast<decltype(_Tp::value)>(_Tp()) == >> _Tp::value> >> >> > + ::value; >> >> > + >> >> > + template<typename _Tp> >> >> > + constexpr size_t __maybe_static_ext = dynamic_extent; >> >> > + >> >> > + template<__integral_constant_like _Tp> >> >> > + constexpr size_t __maybe_static_ext<_Tp> = {_Tp::value}; >> >> >> >> Are the braces here to detect narrowing conversions? >> >> >> >> (The paper doesn't mention why they're used, as far as I can see) >> > >> > The information is in revision history (a bit hidden): >> > Initialized the maybe-static-ext's specialization with {T::value} to >> prevent conversions from negative values. >> >> Thanks. OK for trunk then. >> >> >> >> >> >> >> >> >> >> > + } >> >> > >> >> > template<typename _Type, size_t _ArrayExtent> >> >> > span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>; >> >> > @@ -489,7 +506,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> >> > >> >> > template<contiguous_iterator _Iter, typename _End> >> >> > span(_Iter, _End) >> >> > - -> span<remove_reference_t<iter_reference_t<_Iter>>>; >> >> > + -> span<remove_reference_t<iter_reference_t<_Iter>>, >> >> > + __detail::__maybe_static_ext<_End>>; >> >> > >> >> > template<ranges::contiguous_range _Range> >> >> > span(_Range &&) >> >> > diff --git >> a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc >> b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc >> >> > index e71fdc54230..bca8901685d 100644 >> >> > --- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc >> >> > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/misc.cc >> >> > @@ -97,6 +97,25 @@ test_deduction(Extents... exts) >> >> > VERIFY(e == expected); >> >> > } >> >> > >> >> > +constexpr bool >> >> > +test_integral_constant_deduction() >> >> > +{ >> >> > + auto verify = [](auto actual, auto expected) >> >> > + { >> >> > + static_assert(std::same_as<decltype(actual), >> decltype(expected)>); >> >> > + VERIFY(actual == expected); >> >> > + }; >> >> > + >> >> > + constexpr auto c1 = std::integral_constant<size_t, 1>{}; >> >> > + constexpr auto c2 = std::integral_constant<int, 2>{}; >> >> > + >> >> > + verify(std::extents(1), std::extents<size_t, dyn>{1}); >> >> > + verify(std::extents(c1), std::extents<size_t, 1>{}); >> >> > + verify(std::extents(c2), std::extents<size_t, 2>{}); >> >> > + verify(std::extents(c1, 2), std::extents<size_t, 1, dyn>{2}); >> >> > + return true; >> >> > +} >> >> > + >> >> > constexpr bool >> >> > test_deduction_all() >> >> > { >> >> > @@ -104,6 +123,7 @@ test_deduction_all() >> >> > test_deduction<1>(1); >> >> > test_deduction<2>(1.0, 2.0f); >> >> > test_deduction<3>(int(1), short(2), size_t(3)); >> >> > + test_integral_constant_deduction(); >> >> > return true; >> >> > } >> >> > >> >> > diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc >> b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc >> >> > index 9252273bf66..a650fb19bdf 100644 >> >> > --- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc >> >> > +++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc >> >> > @@ -245,6 +245,28 @@ test_from_pointer_and_shape() >> >> > return true; >> >> > } >> >> > >> >> > +constexpr bool >> >> > +test_from_pointer_and_integral_constant() >> >> > +{ >> >> > + std::array<double, 6> buffer{}; >> >> > + double * ptr = buffer.data(); >> >> > + >> >> > + auto verify = [ptr](auto actual, auto exts) >> >> > + { >> >> > + auto expected = std::mdspan<double, decltype(exts)>(ptr, >> exts); >> >> > + static_assert(std::same_as<decltype(actual), >> decltype(expected)>); >> >> > + VERIFY(actual.extents() == expected.extents()); >> >> > + }; >> >> > + >> >> > + auto c3 = std::integral_constant<int, 3>{}; >> >> > + auto c6 = std::integral_constant<int, 6>{}; >> >> > + >> >> > + verify(std::mdspan(ptr, 6), std::extents(6)); >> >> > + verify(std::mdspan(ptr, c6), std::extents(c6)); >> >> > + verify(std::mdspan(ptr, 2, c3), std::extents(2, c3)); >> >> > + return true; >> >> > +} >> >> > + >> >> > constexpr bool >> >> > test_from_extents() >> >> > { >> >> > @@ -616,6 +638,9 @@ main() >> >> > test_from_pointer_and_shape(); >> >> > static_assert(test_from_pointer_and_shape()); >> >> > >> >> > + test_from_pointer_and_integral_constant(); >> >> > + static_assert(test_from_pointer_and_integral_constant()); >> >> > + >> >> > test_from_extents(); >> >> > static_assert(test_from_extents()); >> >> > >> >> > diff --git a/libstdc++-v3/testsuite/23_containers/span/deduction.cc >> b/libstdc++-v3/testsuite/23_containers/span/deduction.cc >> >> > index dce6cedf89b..c66db90222e 100644 >> >> > --- a/libstdc++-v3/testsuite/23_containers/span/deduction.cc >> >> > +++ b/libstdc++-v3/testsuite/23_containers/span/deduction.cc >> >> > @@ -80,4 +80,7 @@ test01() >> >> > >> >> > std::span s12(const_cast<const std::span<int>&>(s5)); >> >> > static_assert( is_dynamic_span<int>(s12) ); >> >> > + >> >> > + std::span s13(a.data(), std::integral_constant<size_t, 3>{}); >> >> > + static_assert( is_static_span<long, 3>(s13)); >> >> > } >> >> > -- >> >> > 2.49.0 >> >> > >> >> >> >>