[RFC PATCH] libstdc++: Attempt to implement LWG4537 - Improve define_static_array

Hewill Kang hewillk@gmail.com
Mon Mar 30 15:10:44 GMT 2026


I think we also need an explicit static_cast<size_t> for ranges::size(r),
since integer-class types are not implicitly converted to size_t.

Tomasz Kaminski <tkaminsk@redhat.com> 於 2026年3月30日週一 下午10:09寫道:

>
>
> On Mon, Mar 30, 2026 at 3:34 PM Jakub Jelinek <jakub@redhat.com> 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  <jakub@redhat.com>
>>
>>         * 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
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20260330/e88eedbc/attachment.htm>


More information about the Libstdc++ mailing list