[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