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.

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);
+      };
+  } // 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

Reply via email to