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 > >
