diff --git a/xml/issue4483.xml b/xml/issue4483.xml new file mode 100644 index 0000000000..5e305821ec --- /dev/null +++ b/xml/issue4483.xml @@ -0,0 +1,111 @@ + + + + +Multidimensional arrays are not supported by <tt>meta::reflect_constant_array</tt> and related functions +
+ +
+Tomasz KamiƄski +27 Nov 2025 +99 + + +

As any array type (even of structural types) is not considered an structural type, per + 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 + 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.

+
+ + +

+This wording is relative to amended with changes from LWG . +

+ +
    + +
  1. Modify as indicated:

    + +
    +template<ranges::input_range R>
    +  consteval info reflect_constant_array(R&& r);
    +
    +
    +

    -8- Let TU be ranges::range_value_t<R> +and T be remove_all_extents_<U> +ei be static_cast<T>(*iti), +where iti is an iterator to the ith element of `r`. +

    +

    -9- Mandates: +

      +
    • (9.1) — T is a structural type (), + is_constructible_v<T, ranges::range_reference_t<R>> is `true`, and +
    • +
    • (9.2) — `T` satisfies `copy_constructible`, and
    • +
    • (9.3) — if `U` is not an array type, then is_constructible_v<T, ranges::range_reference_t<R>> is `true`.
    • +
    +

    +

    -10- Let `V` be the pack of values of type `info` of the same size as `r`, +where the ith element is +

      +
    • (10.1) — reflect_constant_array(*iti) if U is an array type,
    • +
    • (10.2) — reflect_constant(static_cast<T>(*iti)ei) otherwise,
    • +
    +and iti is an iterator to the ith element of `r`.

    +

    -11- Let P be +

      +
    • (11.1) — If sizeof...(V) > 0 is `true`, then the template parameter object () of type const `T[sizeof...(V)]` + initialized with `{[:V:]...}`, such that constant_of(P[I]) == V...[I] is `true` + for all I in 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 `r` and comparison of such iterator to sentinel. +Any exception thrown by the evaluation of any argument of `reflect_constant`.ei, or +`meta::exception` if evaluation of any reflect_constant(ei)evaluation of +reflect_constant or reflect_constant_array would 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();
    +}
    +
    +
    + +
  2. +
+ +
+ + + +