On Mon, Mar 30, 2026 at 5:19 PM Hewill Kang <[email protected]> wrote:

> We already have __static_sized_range in include/bits/simd_details.h
> <https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/simd_details.h>,
> do we want to reuse it?
> which is currently defined as follows:
>
> template <typename _Tp, size_t _Np = -1uz>
>     concept __static_sized_range
>       = ranges::sized_range<_Tp> && requires(_Tp&& __r) {
> typename integral_constant<size_t, ranges::size(__r)>;
> requires (_Np == -1uz || ranges::size(__r) == _Np);
>       };
>
> I suddenly realized that the current definition rejects the integer-class
> type:
>
> #include <ranges>
> #include <simd>
>
> static_assert(std::simd::__static_sized_range<std::array<int, 4>>);
>
> struct R {
>   static constexpr const int* begin() { return nullptr; }
>   static constexpr const int* end() { return nullptr; }
>   static constexpr std::ranges::__detail::__max_size_type size() { return
> 0; }
> };
>
> static_assert(std::ranges::sized_range<R>);
> static_assert(std::simd::__static_sized_range<R>); // error
>
> https://godbolt.org/z/eYErE3qjY
>
> Should we enhance it to support integer-class type?
>
I do not care abouy contingous-ranges that uses integer-class types, if we
extract
this concept, then yes.

>
>
> Tomasz Kaminski <[email protected]> 於 2026年3月30日週一 下午10:09寫道:
>
>>
>>
>> On Mon, Mar 30, 2026 at 3:34 PM Jakub Jelinek <[email protected]> wrote:
>>
>>> Hi!
>>>
>>> The following patch attempts to implement
>>> https://cplusplus.github.io/LWG/lwg-active.html#4537
>>> Not sure if the concept has the best name or there could be some better
>>> implementation, nor if having auto return type on define_static_array
>>> is acceptable.
>>>
>>> I've added tests for the returned type (though am not sure if that
>>> is correct in all cases or if we don't need further tests).
>>>
>>> In any case, this patch breaks
>>>
>>> FAIL: g++.dg/reflect/range_args.C  -std=c++26 (test for excess errors)
>>> Excess errors:
>>> /usr/src/gcc/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/meta:652:25:
>>> error: no match for call to '(const std::ranges::__access::_Size)
>>> (std::ranges::filter_view<std::span<const char>, bool (*)(char)>&)'
>>> /usr/src/gcc/gcc/testsuite/g++.dg/reflect/range_args.C:75:33: error:
>>> non-constant condition for static assertion
>>> /usr/src/gcc/obj/x86_64-pc-linux-gnu/libstdc++-v3/include/meta:652:25:
>>> error: no match for call to '(const std::ranges::__access::_Size)
>>> (std::ranges::take_while_view<std::span<const char>, bool (*)(char)>&)'
>>> /usr/src/gcc/gcc/testsuite/g++.dg/reflect/range_args.C:76:33: error:
>>> non-constant condition for static assertion
>>> This is on
>>> constexpr std::span<const char> vv = "abcd01234";
>>> constexpr bool not_digit(char c) {
>>>   return c < '0' || c > '9';
>>> }
>>>
>>> static_assert (test_value_range (vv | std::views::filter (not_digit)));
>>> // bidirectional
>>> static_assert (test_value_range (vv | std::views::take_while
>>> (not_digit))); // non-common
>>>
>>> Dunno if this is a filter_view/take_while_view bug, something not thought
>>> out during LWG4537 resolution, bug in the concept or its use, something
>>> else.
>>>
>> The ternary expression does not have not-compiled branches, so
>> ranges::size(__r) needs to always
>> be constant expression.
>> constexpr size_t __extent   = __detail::__statically_sized<_Rg>   ?
>> ranges::size(__r) : dynamic_extent;
>>
>> You can implement it using lambda:
>> constexpr size_t __extent   = [&__r] {
>>   if constexpr (__detail::__statically_sized<_Rg> )
>>      return ranges::size(__r);
>>   else
>>    return dynamic_extent;
>> };
>>
>> But my preference would be to split the whole body:
>> if constexpr (__detail::__statically_sized<_Rg>)
>> {
>>    constexpr size_t __size =   ranges::size(__r) ;
>>    if constexpr (__size > 0)
>>        return  span<const _Tp, __size>(meta::extract<const
>> _Tp(&)[__size]>(__array)); // use span from c-array cosntructor
>>    // you can also use ptr, size
>>   else
>>      return span<const _Tp, 0>(); // default constructor
>> }
>> else // The old code that we already have, without any changes
>>
>>        if (meta::is_array_type(__type))
>> -       return span<const _Tp>(meta::extract<const _Tp*>(__array),
>> -                              meta::extent(__type, 0U));
>>
>>
>>> 2026-03-30  Jakub Jelinek  <[email protected]>
>>>
>>>         * include/std/meta (std::meta::__detail::__statically_sized): New
>>>         concept.
>>>         (std::meta::define_static_array): Change return type to auto.
>>> Use
>>>         __detail::__statically_sized<_Rg> ? ranges::size(__r) :
>>> dynamic_extent
>>>         as second template argument to span, for empty span construct
>>>         span from static_cast<const _Tp*>(nullptr), 0 instead of default
>>>         constructing it.
>>>
>>>         * g++.dg/reflect/define_static_array1.C (l): Another variable
>>>         with define_static_array test from array<int, 0>.
>>>         Add static assertions for types of the define_static_array
>>> results.
>>>
>>> --- libstdc++-v3/include/std/meta.jj    2026-03-30 12:57:50.289580921
>>> +0200
>>> +++ libstdc++-v3/include/std/meta       2026-03-30 15:02:54.818234758
>>> +0200
>>> @@ -632,18 +632,32 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>>>        return meta::extract<const ranges::range_value_t<_Rg>*>(__str);
>>>      }
>>>
>>> +  namespace __detail
>>> +  {
>>> +    template<typename _Rg>
>>> +    concept __statically_sized
>>> +      = requires(_Rg&& __r) {
>>>
>> +       static_cast<char(*)[static_cast<size_t>(ranges::size(__r))
>>> +                           >= 0]>(nullptr);
>>>
>> That nice trick, could you rename it to __static_sized_range, and put it
>> in ranges_base.h?
>> I got problem with my version when imported from module std, do you see
>> the same issue?
>>
>>> +      };
>>> +  } // namespace __detail
>>> +
>>>    template<ranges::input_range _Rg>
>>> -    consteval span<const ranges::range_value_t<_Rg>>
>>> +    consteval auto
>>>      define_static_array(_Rg&& __r)
>>>      {
>>>        using _Tp = ranges::range_value_t<_Rg>;
>>> +      constexpr size_t __extent
>>> +       = __detail::__statically_sized<_Rg>
>>> +         ? ranges::size(__r) : dynamic_extent;
>>>        auto __array = meta::reflect_constant_array(__r);
>>>        auto __type = meta::type_of(__array);
>>>        if (meta::is_array_type(__type))
>>> -       return span<const _Tp>(meta::extract<const _Tp*>(__array),
>>> -                              meta::extent(__type, 0U));
>>> +       return span<const _Tp, __extent>(meta::extract<const
>>> _Tp*>(__array),
>>> +                                        meta::extent(__type, 0U));
>>>        else
>>> -       return span<const _Tp>();
>>> +       return span<const _Tp, __extent>(static_cast<const
>>> _Tp*>(nullptr),
>>> +                                        0);
>>>      }
>>>
>>>    template<class _Tp>
>>> --- gcc/testsuite/g++.dg/reflect/define_static_array1.C.jj
>>> 2026-03-27 10:17:16.120298331 +0100
>>> +++ gcc/testsuite/g++.dg/reflect/define_static_array1.C 2026-03-30
>>> 15:19:15.286549988 +0200
>>> @@ -22,6 +22,7 @@ constexpr auto h = std::define_static_ar
>>>  constexpr auto i = std::define_static_array (std::vector <V> { V { 1,
>>> 2, 3 }, V { 2, 3, 4 }, V { 3, 4, 5 } });
>>>  constexpr auto j = std::define_static_array (std::vector <long long>
>>> {});
>>>  constexpr auto k = std::define_static_array
>>> (std::meta::nonstatic_data_members_of (^^V,
>>> std::meta::access_context::current ()));
>>> +constexpr auto l = std::define_static_array (std::array <int, 0> {});
>>>  static_assert (a.data () == std::define_static_string ("abcd") &&
>>> a.size () == 5);
>>>  static_assert (b.data () == std::define_static_string
>>> (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}")
>>>                && b.size () == sizeof (U"abcd\0ef\N{LATIN CAPITAL LETTER
>>> AE}") / sizeof (char32_t));
>>> @@ -40,6 +41,19 @@ static_assert (h.data () == std::define_
>>>  static_assert (i.size () == 3);
>>>  static_assert (j.data () == nullptr && j.size () == 0);
>>>  static_assert (k.size () == 3 && k[0] == ^^V::a && k[1] == ^^V::b &&
>>> k[2] == ^^V::c);
>>> +static_assert (l.data () == nullptr && l.size () == 0);
>>> +static_assert (type_of (^^a) == ^^const std::span <const char, 5>);
>>> +static_assert (type_of (^^b) == ^^const std::span <const char32_t,
>>> sizeof (U"abcd\0ef\N{LATIN CAPITAL LETTER AE}") / sizeof (char32_t)>);
>>> +static_assert (type_of (^^c) == ^^const std::span <const char,
>>> std::dynamic_extent>);
>>> +static_assert (type_of (^^d) == ^^const std::span <const int, 4>);
>>> +static_assert (type_of (^^e) == ^^const std::span <const float, 6>);
>>> +static_assert (type_of (^^f) == ^^const std::span <const int,
>>> std::dynamic_extent>);
>>> +static_assert (type_of (^^g) == ^^const std::span <const int,
>>> std::dynamic_extent>);
>>> +static_assert (type_of (^^h) == ^^const std::span <const int,
>>> std::dynamic_extent>);
>>> +static_assert (type_of (^^i) == ^^const std::span <const V,
>>> std::dynamic_extent>);
>>> +static_assert (type_of (^^j) == ^^const std::span <const long long,
>>> std::dynamic_extent>);
>>> +static_assert (type_of (^^k) == ^^const std::span <const
>>> std::meta::info, std::dynamic_extent>);
>>> +static_assert (type_of (^^l) == ^^const std::span <const int, 0>);
>>>
>>>  int
>>>  main ()
>>>
>>>         Jakub
>>>
>>>

Reply via email to