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