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