|
| 1 | +<?xml version='1.0' encoding='utf-8' standalone='no'?> |
| 2 | +<!DOCTYPE issue SYSTEM "lwg-issue.dtd"> |
| 3 | + |
| 4 | +<issue num="4483" status="New"> |
| 5 | +<title>Multidimensional arrays are not supported by <tt>meta::reflect_constant_array</tt> and related functions</title> |
| 6 | +<section> |
| 7 | +<sref ref="[meta.define.static]"/> |
| 8 | +</section> |
| 9 | +<submitter>Tomasz Kamiński</submitter> |
| 10 | +<date>27 Nov 2025</date> |
| 11 | +<priority>99</priority> |
| 12 | + |
| 13 | +<discussion> |
| 14 | +<p>As any array type (even of structural types) is not considered an structural type, per |
| 15 | +<sref ref="[temp.param]"/> p12, any invocation of `reflect_constant_array`/`define_static_array` |
| 16 | +with a multidimensional array or `span` of arrays is ill-formed due to the <i>Mandates</i> in |
| 17 | +<sref ref="[meta.define.static]"/> p8 that requires range value type to be structural.</p> |
| 18 | + |
| 19 | +<p>As a consequence, `constant_of` currently supports only single-dimensional arrays |
| 20 | +(<tt>reflect_constant_array</tt> strips outermost extents), while multi-dimensional arrays are |
| 21 | +rejected.</p> |
| 22 | + |
| 23 | +<p>Furthermore, `define_static_object` currently uses <tt>define_static_array(span(addressof(t), 1)).data()</tt>, |
| 24 | +for array types. Since for `T[N]` input this creates an multidimensional `T[1][N]` constant parameter |
| 25 | +object, this function does not support arrays at all. Creating a distinct template |
| 26 | +parameter object leads to emission of (otherwise unnecessary) additional symbols, and breaks the |
| 27 | +invariant that for all supported object types <tt>&constant_of(o) == define_static_object(o)</tt>. |
| 28 | +We should use `reflect_constant_array` for arrays directly.</p> |
| 29 | + |
| 30 | +<p>The <i>Throws</i> clause of `reflect_constant_array` was updated to include any exception |
| 31 | +thrown by iteration over range.</p> |
| 32 | +</discussion> |
| 33 | + |
| 34 | +<resolution> |
| 35 | +<p> |
| 36 | +This wording is relative to <paper num="N5014"/> amended with changes from LWG <iref ref="4432"/>. |
| 37 | +</p> |
| 38 | + |
| 39 | +<ol> |
| 40 | + |
| 41 | +<li><p>Modify <sref ref="[meta.define.static]"/> as indicated:</p> |
| 42 | + |
| 43 | +<pre> |
| 44 | +template<ranges::input_range R> |
| 45 | + consteval info reflect_constant_array(R&& r); |
| 46 | +</pre> |
| 47 | +<blockquote> |
| 48 | +<p>-8- Let <tt><del>T</del><ins>U</ins></tt> be <tt>ranges::range_value_t<R></tt> |
| 49 | +and <ins><tt>T</tt> be <tt>remove_all_extents_<U></tt></ins> |
| 50 | +<del><i>e<sub>i</sub></i> be <tt>static_cast<T>(*<i>it<sub>i</sub></i>)</tt>, |
| 51 | +where <i>it<sub>i</sub></i> is an iterator to the <i>i<sup>th</sup></i> element of `r`</del>. |
| 52 | +</p> |
| 53 | +<p>-9- <i>Mandates</i>: |
| 54 | +<ul style="list-style-type: none"> |
| 55 | +<li><ins>(9.1) —</ins> <tt>T</tt> is a structural type (<sref ref="[temp.param]"/>), |
| 56 | + <del><tt>is_constructible_v<T, ranges::range_reference_t<R>></tt> is `true`, and</del> |
| 57 | +</li> |
| 58 | +<li><ins>(9.2) —</ins> `T` satisfies `copy_constructible`<ins>, and</ins></li> |
| 59 | +<li><ins>(9.3) —</ins> if `U` is not an array type, then <tt>is_constructible_v<T, ranges::range_reference_t<R>></tt> is `true`.</li> |
| 60 | +</ul> |
| 61 | +</p> |
| 62 | +<p>-10- Let `V` be the pack of values of type `info` of the same size as `r`, |
| 63 | +where the <i>i<sup>th</sup></i> element is |
| 64 | +<ul style="list-style-type: none"> |
| 65 | + <li><ins>(10.1) — <tt>reflect_constant_array(*<i>it<sub>i</sub></i>)</tt> if <tt>U</tt> is an array type,</ins></li> |
| 66 | + <li><ins>(10.2) —</ins> <tt>reflect_constant(<ins>static_cast<T>(*<i>it<sub>i</sub></i>)</ins><del><i>e<sub>i</sub></i></del>)</tt><ins> otherwise,</ins></li> |
| 67 | +</ul> |
| 68 | +<ins>and <i>it<sub>i</sub></i> is an iterator to the <i>i<sup>th</sup></i> element of `r`</ins>.</p> |
| 69 | +<p>-11- Let <tt><i>P</i></tt> be |
| 70 | +<ul style="list-style-type: none"> |
| 71 | +<li>(11.1) — If <tt>sizeof...(V) > 0</tt> is `true`, then the template parameter object (<sref ref="[temp.param]"/>) of type const `T[sizeof...(V)]` |
| 72 | + <del>initialized with `{[:V:]...}`</del><ins>, such that <tt>constant_of(<i>P</i>[<i>I</i>]) == V...[<i>I</i>]</tt> is `true` |
| 73 | + for all <tt><i>I</i></tt> in range [`0`, `sizeof...(V)`)</ins>.</li> |
| 74 | +<li>(11.2) — Otherwise, the template parameter object of type <tt>const array<T, 0></tt> initialized with `{}`.</li> |
| 75 | +</ul></p> |
| 76 | +<p>-12- <i>Returns</i>: <tt>^^<i>P</i></tt>.</p> |
| 77 | +<p>-13- <i>Throws</i>: |
| 78 | +<ins>Any exception thrown by increment and dereference operations on iterator to `r` and comparison of such iterator to sentinel.</ins> |
| 79 | +Any exception thrown by the evaluation of any <ins>argument of `reflect_constant`.</ins><del><i>e<sub>i</sub></i>, or</del> |
| 80 | +`meta::exception` if evaluation of any <del><tt>reflect_constant(<i>e<sub>i</sub></i>)</tt></del><ins>evaluation of |
| 81 | +<tt>reflect_constant</tt> or <tt>reflect_constant_array</tt></ins> would exit via an exception. |
| 82 | +</p> |
| 83 | +</blockquote> |
| 84 | +[…] |
| 85 | + |
| 86 | +<pre> |
| 87 | +template<class T> |
| 88 | + consteval const remove_cvref_t<T>* define_static_object(T&& t); |
| 89 | +</pre> |
| 90 | +<blockquote> |
| 91 | +<p>-15- <i>Effects</i>:Equivalent to:</p> |
| 92 | +<pre> |
| 93 | +using U = remove_cvref_t<T>; |
| 94 | +if constexpr (meta::is_class_type(^^U)) { |
| 95 | + return addressof(meta::extract<const U&>(meta::reflect_constant(std::forward<T>(t)))); |
| 96 | +<ins>} else if constexpr (meta::is_array_type(^^U)) { |
| 97 | + return addressof(meta::extract<const U&>(meta::reflect_constant_array(std::forward<T>(t))));</ins> |
| 98 | +} else { |
| 99 | + return define_static_array(span(addressof(t), 1)).data(); |
| 100 | +} |
| 101 | +</pre> |
| 102 | +</blockquote> |
| 103 | + |
| 104 | +</li> |
| 105 | +</ol> |
| 106 | + |
| 107 | +</resolution> |
| 108 | + |
| 109 | + |
| 110 | + |
| 111 | +</issue> |
0 commit comments