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