This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
meta::reflect_constant_array and related functionsSection: 21.4.3 [meta.define.static] Status: New Submitter: Tomasz KamiĆski Opened: 2025-11-27 Last modified: 2025-11-27
Priority: Not Prioritized
View other active issues in [meta.define.static].
View all other issues in [meta.define.static].
View all issues with New status.
Discussion:
As any array type (even of structural types) is not considered an structural type, per
13.2 [temp.param] p12, any invocation of reflect_constant_array/define_static_array
with a multidimensional array or span of arrays is ill-formed due to the Mandates in
21.4.3 [meta.define.static] p8 that requires range value type to be structural.
As a consequence, constant_of currently supports only single-dimensional arrays
(reflect_constant_array strips outermost extents), while multi-dimensional arrays are
rejected.
Furthermore, define_static_object currently uses define_static_array(span(addressof(t), 1)).data(),
for array types. Since for T[N] input this creates an multidimensional T[1][N] constant parameter
object, this function does not support arrays at all. Creating a distinct template
parameter object leads to emission of (otherwise unnecessary) additional symbols, and breaks the
invariant that for all supported object types &constant_of(o) == define_static_object(o).
We should use reflect_constant_array for arrays directly.
The Throws clause of reflect_constant_array was updated to include any exception
thrown by iteration over range.
Proposed resolution:
This wording is relative to N5014 amended with changes from LWG 4432(i).
Modify 21.4.3 [meta.define.static] as indicated:
template<ranges::input_range R> consteval info reflect_constant_array(R&& r);
[…]-8- Let
beTUranges::range_value_t<R>andTberemove_all_extents_<U>ei be.static_cast<T>(*iti), where iti is an iterator to the ith element ofr-9- Mandates:
- (9.1) —
Tis a structural type (13.2 [temp.param]),is_constructible_v<T, ranges::range_reference_t<R>>istrue, and- (9.2) —
Tsatisfiescopy_constructible, and- (9.3) — if
Uis not an array type, thenis_constructible_v<T, ranges::range_reference_t<R>>istrue.-10- Let
Vbe the pack of values of typeinfoof the same size asr, where the ith element isand iti is an iterator to the ith element of
- (10.1) —
reflect_constant_array(*iti)ifUis an array type,- (10.2) —
reflect_constant(static_cast<T>(*iti)otherwise,ei)r.-11- Let
Pbe
- (11.1) — If
sizeof...(V) > 0istrue, then the template parameter object (13.2 [temp.param]) of type constT[sizeof...(V)]initialized with, such that{[:V:]...}constant_of(P[I]) == V...[I]istruefor allIin range [0,sizeof...(V)).- (11.2) — Otherwise, the template parameter object of type
const array<T, 0>initialized with{}.-12- Returns:
^^P.-13- Throws: Any exception thrown by increment and dereference operations on iterator to
rand comparison of such iterator to sentinel. Any exception thrown by the evaluation of any argument ofreflect_constant.ei, ormeta::exceptionif evaluation of anyevaluation ofreflect_constant(ei)reflect_constantorreflect_constant_arraywould exit via an exception.
template<class T> consteval const remove_cvref_t<T>* define_static_object(T&& t);
-15- Effects:Equivalent to:
using U = remove_cvref_t<T>; if constexpr (meta::is_class_type(^^U)) { return addressof(meta::extract<const U&>(meta::reflect_constant(std::forward<T>(t)))); } else if constexpr (meta::is_array_type(^^U)) { return addressof(meta::extract<const U&>(meta::reflect_constant_array(std::forward<T>(t)))); } else { return define_static_array(span(addressof(t), 1)).data(); }