<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<title>Allow initializing aggregates from a parenthesized list of values</title>

	<style type="text/css">
        body { line-height: 135%; }
        address { text-align: right; }
	p {text-align:justify}
	li {text-align:justify}
	blockquote.note
	{
		background-color: #E0E0E0;
		padding-left: 15px;
		padding-right: 15px;
		padding-top: 1px;
		padding-bottom: 1px;
	}
	ins {color: #00A000; text-decoration: none; border-bottom: thin solid #00A000;}
	del {color: #A00000}
        sub, sup { line-height: 100%; }
	</style>
</head>
<body>

<address>
Document number: P0960R3
<br/>
Audience: EWG, CWG
<br/>
<br/>
<a href="mailto:ville.voutilainen@gmail.com">Ville Voutilainen</a><br/>
<a href="mailto:tkoeppe@google.com">Thomas K&ouml;ppe</a><br/>
2019-02-22<br/>
</address>
<hr/>
<h1 align=center>Allow initializing aggregates from a parenthesized list of values</h1>

<h2>Abstract</h2>
<p>
  This paper proposes allowing initializing aggregates from
  a parenthesized list of values; that is, <code>Aggr(val1, val2)</code>
  would mean the same thing as <code>Aggr{val1, val2}</code>, except that
  narrowing conversions are allowed. This is a language fix
  for the problem illustrated in
  <a href="http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4462.html">N4462</a>.
</p>

<h2>Revision history</h2>

<ul>
  <li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0960r0.html">P0960R0</a>: initial version</li>
  <li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0960r1.html">P0960R1</a>: wording created based on EWG feedback from Jacksonville 2018</li>
  <li><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0960r2.html">P0960R2</a>: proposal changed to model an invented constructor call rather than textual transformation to a braced list</li>
  <li>P0960R3 (this revision): proposal changed again to talk directly about initializing elements, but together
    with lifetime extension rules that get close to the model of &ldquo;an invented constructor&rdquo;.
    Also, array size deduction is now explicitly supported, e.g.: <code>int a[](1, 2, 3);</code></li>
</ul>

<h2>Jacksonville 2018 discussion feedback</h2>

<ul>
  <li>Do we want more work in the direction depicted in p0960r0? 12 | 11 | 7 | 1 | 1</li>
  <li>Restrict the change to just dependent types? 1 | 1 | 2 | 13 | 14</li>
  <li>Should designated initializers be supported? 1 | 3 | 12 | 11 | 3</li>
  <li>Should raw arrays be supported? 4 | 14 | 11 | 2 | 1</li>
  <li>Incorporate ban brace-initializing an object if it would be plausible that it would use a deleted constructor? 11 | 14 | 5 | 0 | 3</li>
</ul>

<p>
  Revision R1 implements supporting parenthesized initialization
  for aggregates including arrays, without support for designated initializers.
  The matter of initialization and deleted constructors is handled
  by separate paper(s).
</p>

<h2>Rapperswil 2018 discussion feedback</h2>

<p>From the initial EWG discussion:</p>
<ul>
  <li>P0960R1 as presented: 1 | 2 | 14 | 20 | 3</li>
  <li>P0960R1 but allowing narrowing conversions: 10 | 15 | 13 | 5 | 0</li>
</ul>
<p>After CWG review and feedback:</p>
<ul>
  <li>Accept CWG&rsquo;s recommendation to switch to a &ldquo;as if by constructor&rdquo; model: 18 | 15 | 9 | 2 | 1</li>
  <li>Make <code>std::vector&lt;std::array&lt;int, 3&gt;&gt;().emplace_back(1,
      2, 3)</code> work via language specification: 3 | 1 | 20 | 11 | 11</li>
</ul>
<p>After further CWG feedback and EWG discussion:</p>
<ul>
  <li>Extend lifetimes of temporaries? 1 | 0 | 21 | 11 | 1</li>
  <li>Should evaluation occur in-order? 5 | 12 | 10 | 7 | 1</li>
  <li>Make aggregate initialization preferable over conversions? 1 | 2 | 15 | 11 | 3</li>
  <li>Make it  behave <em>exactly</em> like a constructor, e.g.
    indeterminate evaluation order, non-extension of lifetime?
    9 | 12 | 8 | 3 | 1
  </li>
  <li>Should the constructor be non-explicit? 3 | 2 | 12 | 9 | 4</li>
</ul>

<p>
  This revision changes the mental model from the original &ldquo;literal rewrite
  to a braced list&rdquo; to &ldquo;as if a synthesized, explicit constructor with
  appropriate <em>mem-initializer</em>s was called&rdquo;.
  This has the effect of allowing narrowing conversions in the parenthesized list,
  even when narrowing conversions would be forbidden in the corresponding
  braced list syntax. It also clarifies the non-extension of temporary lifetimes
  of temporaries bound to references, the absence of brace elision, and the absence
  of a well-defined order of evaluation of the arguments.
</p>

<p>During the discussion, it was suggested by CWG that we should even break an existing
  corner case: Given <code>struct A; struct C { operator A(); }; struct A { C c; };</code>,
  the declaration <code>A a(c);</code> currently invokes <code>C</code>&rsquo;s
  conversion function to <code>A</code>. It was suggested to change this behaviour to use
  the (arguably better-matching) aggregate initialization in this case, i.e. to behave
  like <code>A a{c};</code> and not like <code>A a = c;</code>. There was, however, no
  consensus to pursue this direction, and the proposal remains a pure extension at this
  point.</p>

<h2>San Diego 2018 discussion feedback</h2>

<p>In San Diego, EWG only briefly revisited the latest revision of the Rapperswil work
  (then D0960R2), and reconfirmed the direction of modelling an invented constructor.
  It was explicitly requested to ensure that direct member initializers work as expected,
  and that the resulting initialization can be used in constant evaluation (if possible).

<h2>Kona 2019 CWG review feedback</h2>

<p>During CWG review in Kona, it became clear that the previously proposed &ldquo;synthesized
  constructor&rdquo; was problematic. The initially suggested constructor was (in the notation
  of the proposed wording):</p>
<blockquote>
  <code>explicit A(T</code><sub>1</sub><code>&amp;&amp; t</code><sub>1</sub><code>,</code>
  &hellip; <code>, T</code><sub><em>k</em></sub><code>&amp;&amp; t</code><sub><em>k</em></sub><code>);</code>
</blockquote>
<p>But that constructor is inappropriate, since it does not allow non-reference members to
  be initialized with lvalues. A fix would be to drop the rvalue-references and instead use:</p>
<blockquote>
  <code>explicit A(T</code><sub>1</sub><code> t</code><sub>1</sub><code>,</code>
  &hellip; <code>, T</code><sub><em>k</em></sub><code> t</code><sub><em>k</em></sub><code>);</code>
</blockquote>
<p>But even if the elements are direct-initialized with
  <code>static_cast&lt;T</code><sub><em>i</em></sub><code>&amp;&amp;&gt;(t</code><sub><em>i</em></sub><code>)</code>,
  this approach would have required a mandatory additional move from the parameter variable, which
  would have removed the solution further from the design goal of being &ldquo;just like brace
  initialization&rdquo;.
  In light of this, CWG chose to abandon the approach of an invented constructor and
  reverted to a direct specification of the initialization of the aggregate elements
  from the initializers. The issue of lifetime extension of temporaries is now addressed
  by explicitly adding an exception to the lifetime rules ([class.temporary, 6.6.7]/6).
  Moreover, the order of evaluation is again specified to be deterministic, in 
  left-to-right order, so as to not cause undue lack of exception safety compared
  to brace initialization. Even though users should not specifically rely on this
  order, it would have been needlessly dangerous to make the behaviour different from
  that of brace initialization, and implementations would have been unlikely to
  perform evaluation in any other order anyway.</p>
  
<h2>Design principles</h2>

<ul>
  <li>Any existing meaning of <code>A(b)</code> should not change.</li>
  <li>Parenthesized initialization and braced-initialization should
    be as similar as possible, but as distinct as necessary to conform with
    the existing mental models of braced lists and parenthesized lists.</li>
  <li>In particular, we have the following differences:
    <ul>
      <li>For an aggregate <code>A</code>, <code>A{b}</code> will not convert
        <code>b</code> to <code>A</code>, unless <code>b</code> is of type
        <code>A</code> or type derived from <code>A</code>. <code>A(b)</code>
        will convert even in other cases. This difference applies only to non-arrays.</li>
      <li>Aggregate-initialization <code>A{x, y, x}</code> forbids narrowing conversions,
        while the new syntax <code>A(x, y, z)</code> does allow narrowing.</li>
      <li>A temporary bound to a reference member of the aggregate via braces has its
        lifetime extended, whereas no extension happens when the temporary is passed
        via round parentheses.</li>
    </ul>
  </li>
</ul>

<h2>Wording</h2>

<p>In [class.temporary, 6.6.7]/6, add a new bullet (6.?) between (6.9) and (6.10) as follows:</p>
<blockquote>
  The exceptions to this lifetime rule are:
  <ul>
    <li>A temporary object bound to a reference parameter in a function call (7.6.1.2)
      persists until the completion of the full-expression containing the call.</li>
    <li><ins>A temporary object bound to a reference element of an aggregate of class type
      initialized from a parenthesized <em>expression-list</em> [dcl.init, 9.3] persists until
      the completion of the full-expression containing the <em>expression-list</em>.</ins></li>
    <li>The lifetime of a temporary bound to the returned value [&hellip;]</li>
  </ul>
</blockquote>

<p>In [dcl.init, 9.3]/(17.5), edit as follows:</p>
<blockquote>
  Otherwise, if the destination type is an array, the
  <del>program is ill-formed</del><ins>object is initialized as follows.
  Let <em>x</em><sub>1</sub>, &hellip;, <em>x</em><sub><em>k</em></sub>
  be the elements of the <em>expression-list</em>. If the destination type
  is an array of unknown bound, it is defined as having <em>k</em>
  elements. If <em>k</em> is greater than the size of the array, the program is
  ill-formed. Otherwise, the <em>i</em><sup>th</sup> array element is copy-initialized
  with <em>x</em><sub><em>i</em></sub> for each
  1&nbsp;&le;&nbsp;<em>i</em>&nbsp;&le;&nbsp;<em>k</em>, and value-initialized for
  each <em>k</em>&nbsp;&lt;&nbsp;<em>i</em>&nbsp;&le;&nbsp;<em>n</em>.

  For each 1&nbsp;&le;&nbsp;<em>i</em>&nbsp;&lt;&nbsp;<em>j</em>&nbsp;&le;&nbsp;<em>n</em>,
  every value computation and side effect associated with the initialization of
  the <em>i</em><sup>th</sup> element of the array is sequenced before those associated with
  the initialization of the <em>j</em><sup>th</sup> element</ins>.
</blockquote>

<p>In [dcl.init, 9.3]/(17.6.2), edit as follows:</p>
<blockquote>
  Otherwise, if the initialization is direct-initialization, or if it is copy-initialization
  where the cv-unqualified version of the source type is the same class as, or a derived class
  of, the class of the destination, constructors are considered. The applicable constructors are
  enumerated (16.3.1.3), and the best one is chosen through overload resolution (16.3). The
  constructor so selected is called to initialize the object, with the initializer expression or
  expression-list as its argument(s). If no constructor applies<ins> and the destination type is
  not an aggregate</ins>, or the overload resolution is ambiguous, the initialization is
  ill-formed.
</blockquote>

<p>After [dcl.init, 9.3]/(17.6.3)  insert a new sub-bullet (17.6.?) as follows:</p>
<blockquote>
  <ins>Otherwise, if the destination type is a (possibly cv-qualified) aggregate
    class <code>A</code> and the initializer is a parenthesized <em>expression-list</em>, the
    object is initialized as follows. Let
    <em>e</em><sub>1</sub>, &hellip;, <em>e</em><sub><em>n</em></sub>
    be the elements of the aggregate [dcl.init.aggr, 9.3.1].

    Let <em>x</em><sub>1</sub>, &hellip;, <em>x</em><sub><em>k</em></sub>
    be the elements of the <em>expression-list</em>. If <em>k</em> is greater
    than <em>n</em>, the program is ill-formed.
    
    The element <em>e</em><sub><em>i</em></sub> is copy-initialized
    with <code>x</code><sub><em>i</em></sub> for
    1&nbsp;&le;&nbsp;<em>i</em>&nbsp;&le;&nbsp;<em>k</em>. The remaining elements are
    initialized with their default member initializers, if any, and otherwise are
    value-initialized.

    For each 1&nbsp;&le;&nbsp;<em>i</em>&nbsp;&lt;&nbsp;<em>j</em>&nbsp;&le;&nbsp;<em>n</em>,
    every value computation and side effect associated with the initialization of
    <em>e<sub>i</sub></em> is sequenced before those associated with the initialization of
    <em>e<sub>j</sub></em>.

    [<em>Note</em>: By contrast with direct-list-initialization, narrowing conversions
    [dcl.init.list, 9.3.4] are permitted, designators are not permitted,
    a temporary object bound to a reference does not have its lifetime extended
    [class.temporary, 6.6.7], and there is no brace elision. [<em>Example</em>:</ins>
  <blockquote><code><ins>struct A {</ins><br>
        &nbsp; <ins>int a;</ins><br>
        &nbsp; <ins>int&amp;&amp; r;</ins><br>
      <ins>};<br><br>
      int f();<br>
      int n = 10;<br><br>
      A a1{1, f()}; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // OK, lifetime is extended<br>
      A a2(1, f()); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // well-formed, but dangling reference<br>
      A a3{1.0, 1}; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // error: narrowing conversion<br>
      A a4(1.0, 1); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // well-formed, but dangling reference<br>
      A a5(1.0, std::move(n)); &nbsp; &nbsp;// OK<br>
      </ins></code></blockquote>
  <ins>&mdash;&nbsp;<em>end example</em>] &mdash;&nbsp;<em>end note</em>]</ins>
</blockquote>

<p>In [cpp.predefined, 14.8] Table 17, add the following feature test macro:</p>
<blockquote>
  <ins><code>__cpp_aggregate_paren_init 201902L</code></ins>
</blockquote>

<h2>Acknowledgements</h2>
<p>Great many thanks to the members of the Core Working Group for their thorough
  and diligent work across many rounds of wording review in Rapperswil and in Kona,
  and to Tomasz Kami&#324;ski for valuable feedback.</p>

</body>
</html>
