<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2157: How does std::array&lt;T,0&gt; initialization work when T is not default-constructible?</title>
<meta property="og:title" content="Issue 2157: How does std::array&lt;T,0&gt; initialization work when T is not default-constructible?">
<meta property="og:description" content="C++ library issue. Status: Open">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2157.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#Open">Open</a> status.</em></p>
<h3 id="2157"><a href="lwg-active.html#2157">2157</a>. How does <code>std::array&lt;T,0&gt;</code> initialization work when <code>T</code> is not default-constructible?</h3>
<p><b>Section:</b> 23.3.3.5 <a href="https://wg21.link/array.zero">[array.zero]</a> <b>Status:</b> <a href="lwg-active.html#Open">Open</a>
 <b>Submitter:</b> Daryle Walker <b>Opened:</b> 2012-05-08 <b>Last modified:</b> 2021-03-14</p>
<p><b>Priority: </b>3
</p>
<p><b>View other</b> <a href="lwg-index-open.html#array.zero">active issues</a> in [array.zero].</p>
<p><b>View all other</b> <a href="lwg-index.html#array.zero">issues</a> in [array.zero].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#Open">Open</a> status.</p>
<p><b>Discussion:</b></p>

<p>
Objects of <code>std::array&lt;T, N&gt;</code> are supposed to be initialized with aggregate initialization (when 
not the destination of a copy or move). This clearly works when <code>N</code> is positive. What happens when <code>N</code> 
is zero?  To continue using an (inner) set of braces for initialization, a <code>std::array&lt;T, 0&gt;</code> implementation 
must have an array member of at least one element, and let default initialization take care of those secret elements.  
This cannot work when <code>T</code> has a set of constructors and the default constructor is deleted from that set.
Solution: Add a new paragraph in 23.3.3.5 <a href="https://wg21.link/array.zero">[array.zero]</a>:
</p>
<blockquote>
<p>
The unspecified internal structure of array for this case shall allow initializations like:
</p>
<blockquote><pre>
array&lt;T, 0&gt; a = { };
</pre></blockquote>
<p>
and said initializations must be valid even when <code>T</code> is not default-constructible.
</p>
</blockquote>

<p><i>[2012, Portland: Move to Open]</i></p>

<p>
Some discussion to understand the issue, which is that implementations currently have freedom to implement
an empty <code>array</code> by holding a dummy element, and so might not support value initialization, which is
surprising when trying to construct an empty container. However, this is not mandated, it is an unspecified
implementation detail.
</p>

<p>
Jeffrey points out that the implication of 23.3.3.1 <a href="https://wg21.link/array.overview">[array.overview]</a> is that this initialization syntax
must be supported by empty <code>array</code> objects already. This is a surprising inference that was not
obvious to the room, but consensus is that the reading is accurate, so the proposed resolution is not necessary,
although the increased clarity may be useful.
</p>

<p>
Further observation is that the same clause effectively implies that <code>T</code> must always be DefaultConstructible,
regardless of <code>N</code> for the same reasons - as an <i>initializer-list</i> may not supply enough values, and the
remaining elements must all be value initialized.
</p>

<p>
Concern that we are dancing angels on the head of pin, and that relying on such subtle implications in wording is
not helpful. We need a clarification of the text in this area, and await wording.
</p>

<p><i>[2015-02 Cologne]</i></p>

<p>
DK: What was the outcome of Portland? AM: Initially we thought we already had the intended behaviour. 
We concluded that <code>T</code> must always be <code>DefaultConstructible</code>, but I'm not sure why. GR: It's p2 in 
<code>std::array</code>, "up to <code>N</code>". AM: That wording already implies that "<code>{}</code>" has to work when <code>N</code> 
is zero. But the wording of p2 needs to be fixed to make clear that it does <em>not</em> imply that <code>T</code> must be 
<code>DefaultConstructible</code>.
<p/>
Conclusion: Update wording, revisit later. 
</p>

<p><i>[2015-10, Kona Saturday afternoon]</i></p>

<p>MC: How important is this? Can you not just use default construction for empty arrays? </p>
<p>TK: It needs to degenerate properly from a pack. STL agrees.</p> 
<p>JW: Yes, this is important, and we have to make it work.</p>
<p>MC: I hate the words "initialization like". </p>
<p>JW: I'll reword this.</p>
<p>WEB: Can I ask that once JW has reworded this we move it to Review rather than Open? </p>
<p>MC: We'll try to review it in a telecon and hopefully get it to tentatively ready.</p>
<p>STL: Double braces must also work: <code>array&lt;T, 0&gt; a = {{}};</code>.</p>
<p>Jonathan to reword.</p>

<p><i>[2018-03-14 Wednesday evening issues processing]</i></p>

<p>Jens suggested that we remove the requirement that <code>begin() == end() == </code><i>unique-value</i>, 
specifically the unique value part.</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>This wording is relative to <a href="https://wg21.link/n3376">N3376</a>.</p>

<p>Add the following new paragraph between the current 23.3.3.5 <a href="https://wg21.link/array.zero">[array.zero]</a> p1 and p2:</p>

<blockquote>
<p>
-1- <code>array</code> shall provide support for the special case <code>N == 0</code>.
<p/>
<ins>-?- The unspecified internal structure of <code>array</code> for this case shall allow initializations like:</ins>
</p>
<blockquote><pre>
<ins>array&lt;T, 0&gt; a = { };</ins>
</pre></blockquote>
<p>
<ins>and said initializations must be valid even when <code>T</code> is not default-constructible.</ins>
<p/>
-2- In the case that <code>N == 0</code>, <code>begin() == end() ==</code> unique value. The return value of 
<code>data()</code> is unspecified.
<p/>
-3- The effect of calling <code>front()</code> or <code>back()</code> for a zero-sized array is undefined.
<p/>
-4- Member function <code>swap()</code> shall have a <em>noexcept-specification</em> which is equivalent to 
<code>noexcept(true)</code>.
</p>
</blockquote>
</blockquote>

<p><i>[2018-06-14, Jonathan Wakely comments and provides revised wording]</i></p>

<p>
The new wording does not address the 2018-03-14 suggestion from Jens to remove the unique value. It wasn't
clear to me that there was consensus to make that change, and it would be a change in behaviour not just a 
clarification of the existing wording.
</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>
This wording is relative to <a href="https://wg21.link/n4750">N4750</a>.
</p>

<p>Modify 23.3.3.5 <a href="https://wg21.link/array.zero">[array.zero]</a> as indicated:</p>

<blockquote>
<p>
-1- <code>array</code> <del>shall</del> provide<ins>s</ins> support for the special case <ins>of a zero-sized <code>array</code> 
that is always empty, i.e.</ins> <code>N == 0</code><ins>, with the properties described in this subclause</ins>.
<p/>
<ins>-?- A zero-sized <code>array</code> type is an aggregate that meets the <code>DefaultConstructible</code> (Table 22) and 
<code>CopyConstructible</code> (Table 24) requirements. There is a single element of the aggregate, of an unspecified 
<code>DefaultConstructible</code> type. [<i>Note:</i> This allows initialization of the form <code>array&lt;T, 0&gt; a = {{}};</code>. 
There is no requirement for <code>T</code> to be <code>DefaultConstructible</code>. &mdash; <i>end note</i>]</ins>
<p/>
-2- <del>In the case that <code>N == 0</code>, <code>begin() == end() ==</code> unique value</del><ins><code>begin()</code> and 
<code>end()</code> return non-dereferenceable iterators such that <code>begin() == end()</code> and <code>a.begin() != b.begin()</code> 
where <code>a</code> and <code>b</code> are distinct objects of the same zero-sized <code>array</code> type</ins>. The return value 
of <code>data()</code> is unspecified.
<p/>
-3- The effect of calling <code>front()</code> or <code>back()</code> for a zero-sized array is undefined.
<p/>
-4- Member function <code>swap()</code> <del>shall have</del><ins>has constant complexity and</ins> a non-throwing exception specification.
</p>
</blockquote>
</blockquote>

<p><i>[2018-08-30, Jonathan revises wording following feedback from Daniel Kruegler and Tim Song.]</i></p>

<p>
Daniel noted that it's undefined to compare iterators from different containers,
so <code>a.begin() != b.begin()</code> can't be used. That means whether the iterators
from different containers are unique is unobservable anyway.
We can say they don't share the same underlying sequence, which tells users they can't compare them
and tells implementors they can't return value-initialized iterators.
<br/>
Tim noted that it's not sufficient to say the unspecified type in a zero-sized array is DefaultConstructible,
it also needs to be constructible from <code>= {}</code>. Also, a zero-sized array should be CopyAssignable.
</p>

<p><strong>Previous resolution [SUPERSEDED]:</strong></p>
<blockquote class="note">
<p>
This wording is relative to <a href="https://wg21.link/n4762">N4762</a>.
</p>

<p>Modify 23.3.3.5 <a href="https://wg21.link/array.zero">[array.zero]</a> as indicated:</p>

<blockquote>
<p>
-1- <code>array</code> <del>shall</del> provide<ins>s</ins> support for the special case <ins>of a zero-sized <code>array</code> 
that is always empty, i.e.</ins> <code>N == 0</code><ins>, with the properties described in this subclause</ins>.
<p/>
<ins>-?- A zero-sized <code>array</code> type is an aggregate that meets the <i>Cpp17DefaultConstructible</i> (Table 24) and 
<i>Cpp17CopyConstructible</i> (Table 26) and <i>Cpp17CopyAssignable</i> (Table 28) requirements. There is a single element 
of the aggregate, of an unspecified <i>Cpp17DefaultConstructible</i> type that is copy-list-initializable from an empty list.
[<i>Note:</i> This allows initialization of the form <code>array&lt;T, 0&gt; a = {{}};</code>. There is no requirement for 
<code>T</code> to be <i>Cpp17DefaultConstructible</i>. &mdash; <i>end note</i>]</ins>
<p/>
-2- <del>In the case that <code>N == 0</code>, <code>begin() == end() ==</code> unique value</del><ins><code>begin()</code> and <code>end()</code> 
return non-dereferenceable iterators such that <code>begin() == end()</code>. When <code>a</code> and <code>b</code> are distinct objects 
of the same zero-sized <code>array</code> type, <code>a.begin()</code> and <code>b.begin()</code> are not iterators over the same 
underlying sequence. [<i>Note:</i> Therefore <code>begin()</code> does not return a value-initialized iterator &mdash; 
<i>end note]</i></ins>. The return value of <code>data()</code> is unspecified.
<p/>
-3- The effect of calling <code>front()</code> or <code>back()</code> for a zero-sized array is undefined.
<p/>
-4- Member function <code>swap()</code> <del>shall have</del><ins>has constant complexity and</ins> a non-throwing exception specification.
</p>
</blockquote></blockquote>

<p><i>[2021-03-14; Johel Ernesto Guerrero Pe&ntilde;a comments and provides improved wording]</i></p>

<p>
The currently proposed wording specifies:
</p>
<blockquote><p>
There is a single element of the aggregate, of an unspecified <i>Cpp17DefaultConstructible</i> 
type that is copy-list-initializable from an empty list.
</p></blockquote>
<p>
This doesn't specify which expressions involving zero-sized array specializations are constant expressions. 
23.3.3.1 <a href="https://wg21.link/array.overview">[array.overview]</a> p4 specifies <code>array&lt;T, 0&gt;</code> to be a structural type when <code>T</code> 
is a structural type. This requires that its single element, let's call it <i>single-element</i>, be a 
structural type. But that says nothing about which of the special member functions of <i>single-element</i> 
are constant expressions. By being a structural type, <i>single-element</i> is permitted to be implemented 
as a literal class type. To meet this requirement, <i>single-element</i> can be implemented to have one 
constexpr constructor that is not a copy or move constructor (6.9.1 <a href="https://wg21.link/basic.types.general">[basic.types.general]</a> p10), so 
its default constructor needn't be constexpr. This is unlike non-zero-sized array specializations, which 
inherit these properties from <code>T</code>. Furthermore, this permits an implementation of <i>single-element</i> 
whose default constructor stores the result of <code>std::source_location::current()</code> in a data member 
(as exemplified in the specification for <code>current</code>). <i>Cpp17DefaultConstructible</i> doesn't 
require the default constructor to produce equal values. The simplest way to solve these issues and any other 
that might arise from future changes and oversights would be to specify <i>single-element</i> as an empty 
aggregate type. Then the wording from 23.3.3.2 <a href="https://wg21.link/array.cons">[array.cons]</a> p1 makes it clear that all the special 
member functions are constant expressions. It would also mean that the default constructor produces 
template-argument-equivalent values.
</p>


<p id="res-2157"><b>Proposed resolution:</b></p>
<p>
This wording is relative to <a href="https://wg21.link/n4878">N4878</a>.
</p>

<p>Modify 23.3.3.5 <a href="https://wg21.link/array.zero">[array.zero]</a> as indicated:</p>

<ol>
<li>
<blockquote>
<p>
-1- <code>array</code> <del>shall</del> provide<ins>s</ins> support for the special case <ins>of a zero-sized <code>array</code> 
that is always empty, i.e.</ins> <code>N == 0</code><ins>, with the properties described in this subclause</ins>.
<p/>
<ins>-?- A zero-sized <code>array</code> type is an aggregate that meets the <i>Cpp17DefaultConstructible</i> 
(Table 29 [tab:cpp17.defaultconstructible]) and <i>Cpp17CopyConstructible</i> (Table 31 [tab:cpp17.copyconstructible]) 
and <i>Cpp17CopyAssignable</i> (Table 33 [tab:cpp17.copyassignable]) requirements. There is a single element 
of the aggregate, of an unspecified empty aggregate type. [<i>Note:</i> This allows initialization of the form 
<code>array&lt;T, 0&gt; a = {{}};</code>. There is no requirement for <code>T</code> to be <i>Cpp17DefaultConstructible</i>. 
&mdash; <i>end note</i>]</ins>
<p/>
-2- <del>In the case that <code>N == 0</code>, <code>begin() == end() ==</code> unique value</del><ins><code>begin()</code> and 
<code>end()</code> return non-dereferenceable iterators such that <code>begin() == end()</code>. When <code>a</code> and <code>b</code> 
are distinct objects of the same zero-sized <code>array</code> type, <code>a.begin()</code> and <code>b.begin()</code> are not iterators 
over the same underlying sequence. [<i>Note:</i> Therefore <code>begin()</code> does not return a value-initialized iterator 
&mdash; <i>end note</i>].</ins>. The return value of <code>data()</code> is unspecified.
<p/>
-3- The effect of calling <code>front()</code> or <code>back()</code> for a zero-sized array is undefined.
<p/>
-4- Member function <code>swap()</code> <del>shall have</del><ins>has constant complexity and</ins> a non-throwing exception 
specification.
</p>
</blockquote>
</li>
</ol>






</body>
</html>
