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