Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h3>TL;DR</h3> <pre><code>template&lt;typename T, int N&gt; using raw_array = T[N]; auto &amp;&amp;z = raw_array&lt;int,5&gt;{}; </code></pre> <hr> <p>Your example of <code>auto z = int[5];</code> isn't legal any more than <code>auto z = int;</code> is, simply because a type is not a valid initializer. You can write: <code>auto z = int{};</code> because <code>int{}</code> is a valid initializer.</p> <p>Once one realizes this, the next attempt would be:</p> <pre><code>auto z = int[5]{}; </code></pre> <p>Note that your <code>int y[5]</code> does not have any initializer. If it had then you would have jumped straight here.</p> <p>Unfortunately this does not work either for obscure syntax reasons. Instead you must find a legal way to name the array type in an initializer. For example, a typedef name can be used in an initializer. A handy reusable <em>template type alias</em> eliminates the burdensome requirement of a new typedef for every array type:</p> <pre><code>template&lt;typename T, int N&gt; using raw_array = T[N]; auto z = raw_array&lt;int,5&gt;{}; </code></pre> <hr> <p>Aside: You can use template type aliases to fix the weird 'inside-out' syntax of C++, allowing you to name any compound type in an orderly, left-to-right fashion, by using <a href="https://groups.google.com/a/isocpp.org/forum/?fromgroups#!searchin/std-proposals/left$20to$20right$20type$20syntax/std-proposals/xDQR3y5uTZ0/VKmOiLRzHqkJ" rel="nofollow noreferrer">this proposal</a>.</p> <hr> <p>Unfortunately due to the design bug in C and C++ which causes array-to-pointer conversions at the drop of a hat, the deduced type of the variable <code>z</code> is <code>int*</code> rather <code>int[5]</code>. The resulting variable becomes a dangling pointer when the temporary array is destroyed.</p> <p>C++14 introduces <code>decltype(auto)</code> which uses different type deduction rules, correctly deducing an array type:</p> <pre><code>decltype(auto) z = raw_array&lt;int,5&gt;{}; </code></pre> <p>But now we run into another design bug with arrays; they do not behave as proper objects. You can't assign, copy construct, do pass by value, etc., with arrays. The above code is like saying:</p> <pre><code>int g[5] = {}; int h[5] = g; </code></pre> <p>By all rights this should work, but unfortunately built-in arrays <a href="https://stackoverflow.com/a/10253277/365496">behave bizarrely</a> in C and C++. In our case, the specific problem is that arrays are not allowed to have just any kind of initializer; they are strictly limited to using initializer lists. An array temporary, initialized by an initializer list, is not itself an initializer list.</p> <hr> <h3>Answer 1:</h3> <p>At this point Johannes Schaub makes the excellent suggestion that we can use temporary lifetime extension.</p> <pre><code>auto &amp;&amp;z = raw_array&lt;int,5&gt;{}; </code></pre> <p><code>decltype(auto)</code> isn't needed because the addition of <code>&amp;&amp;</code> changes the deduced type, so Johannes Schaub's suggestion works in C++11. This also avoids the limitation on array initializers because we're initializing a reference instead of an array.</p> <p>If you want the array to deduce its length from an initializer, you can use an incomplete array type:</p> <pre><code>template&lt;typename T&gt; using unsized_raw_array = T[]; auto &amp;&amp;z = unsized_raw_array&lt;int&gt;{1, 2, 3}; </code></pre> <hr> <p>Although the above does what you want you may prefer to avoid raw arrays entirely, due to the fact that raw arrays do not behave like proper C++ objects, and the obscurity of their behavior and the techniques used above.</p> <h3>Answer 2:</h3> <p>The <code>std::array</code> template in C++11 does act like a proper object, including assignment, being passable by value, etc., and just generally behaving sanely and consistently where built-in arrays do not.</p> <pre><code>auto z = std::array&lt;int,5&gt;{}; </code></pre> <p>However, with this you miss out on being able to have the array type infer its own length from an initializer. Instead You can write a <code>make_array</code> template function that does the inference. Here's a really simple version I haven't tested and which doesn't do things you might want, such as verify that all the arguments are the same type, or let you explicitly specify the type.</p> <pre><code>template&lt;typename... T&gt; std::array&lt;typename std::common_type&lt;T...&gt;::type, sizeof...(T)&gt; make_array(T &amp;&amp;...t) { return {std::forward&lt;T&gt;(t)...}; } auto z = make_array(1,2,3,4,5); </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload