<!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: P0960R2
<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-01-21<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>P0960R0 - initial version</li>
  <li>P0960R1 - wording created based on EWG feedback from Jacksonville 2018</li>
  <li>P0960R2 - proposal changed to model an invented constructor call rather than textual transformation to a braced list</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>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>
      <li>The elements of the braced list are evaluated in order, whereas parenthesized lists
        usually carry the connotation of indeterminate evaluation order (like for a
        function call). However, the evaluation order will necessarily be definite
        in this situation because aggregate elements are initialized in order, and directly
        from the corresponding initializer elements.</li>
    </ul>
  </li>
</ul>

<h2>Wording</h2>

<p>In [dcl.init]/17, delete item (17.5):</p>
<blockquote>
  <del>Otherwise, if the destination type is an array, the program is ill-formed.</del>
</blockquote>

<p>In [dcl.init]/(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]/(17.6.3) and before [dcl.init]/(17.7), insert a new
  top-level bullet as follows:</p>
<blockquote>
    <ins>If the destination type is an aggregate and the initializer
      is a parenthesized <em>expression-list</em> and no viable constructor was found
      above, 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 the aggregate [dcl.init.aggr],
      and let <code>T</code><sub>1</sub>, &hellip;, <code>T</code><sub><em>n</em></sub> be
      their respective declared types.
      
      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.

      For each integer 1&nbsp;&le;&nbsp;<code>i</code>&nbsp;&le;&nbsp;<code>N</code>,
      let <em>v<sub>i</sub></em> be the empty token sequence, unless the destination type
      is a class type and <em>e<sub>i</sub></em> has a default member initializer [class.mem],
      in which case <em>v<sub>i</sub></em> consists of the same tokens as that default member initializer.
    </ins>
    <ul>
        <li><ins>If the destination is an array of type <code>U[N]</code>, then for each
          integer 0&nbsp;&le;&nbsp;<em>i</em>&nbsp;&lt;&nbsp;<em>k</em>, the <em>i</em><sup>th</sup> element
          is copy-initialized with <em>x</em><sub><em>i</em>+1</sub>,
          and for each integer <em>k</em>&nbsp;&le;&nbsp;<em>i</em>&nbsp;&lt;&nbsp;<code>N</code>,
            the <em>i</em><sup>th</sup> element is direct-list-initialized with <code>{}</code>.</ins>
        </li>
        <li><ins>Otherwise, the destination type is a (possibly cv-qualified) class type <code>A</code>.
          Given an invented, public constructor of the form
          <blockquote>
            <ins><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><em>e</em><sub>1</sub><code>(std::forward&lt;T</code><sub>1</sub><code>&gt;(t</code><sub>1</sub><code>)), </code>
              &hellip; <code>, </code><em>e</em><sub><em>k</em></sub><code>(std::forward&lt;T</code><sub><em>k</em></sub><code>&gt;(t</code><sub><em>k</em></sub><code>)),</code>
              <em>e</em><sub><em>k</em>+1</sub><code>(</code><em>v</em><sub><em>k</em>+1</sub><code>),</code>
              &hellip; <code>, </code><em>e</em><sub><em>n</em></sub><code>(</code><em>v</em><sub><em>n</em></sub><code>)) {}</code></ins>
          </blockquote>
          that is a constexpr constructor [dcl.constexpr] if it satisfies the requirements for a constexpr constructor,
          then if the expression
          <code>A(</code><em>x</em><sub>1</sub>, &hellip;, <em>x</em><sub><em>k</em></sub><code>)</code>
          is ill-formed, the program is ill-formed. Otherwise, the object is initialized as if by
          <code>A(</code><em>x</em><sub>1</sub>, &hellip;, <em>x</em><sub><em>k</em></sub><code>)</code>.</ins>
        </li>
      </ul>
    
      <ins>[<em>Note</em>: Designators are not permitted. By contrast with
      direct-list-initialization, narrowing conversions [dcl.list.init]
      are permitted, the order of evaluation of the list elements is
      indeterminate, a temporary object [class.temporary] bound to a
      reference does not have its lifetime extended, 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><br>
      A a1{1, f()}; &nbsp; &nbsp;  // OK<br>
      A a2{1.0, 1}; &nbsp; &nbsp;  // Error, narrowing conversion<br>
      A a2(1.0, f()); &nbsp; // well-formed, but dangling reference
      </ins></code></blockquote>
      <ins>&mdash;&nbsp;<em>end example</em>] &mdash;&nbsp;<em>end note</em>]</ins>
  </blockquote>

<p>
  Drafting note: the note in the above wording can easily be left out - the
  grammar of a parenthesized initialization does not allow designators.
  The note is added just for explanatory clarity.
</p>

<!-- tkoeppe, CWG notes

 *** Round 1 (Tuesday) ***

 * Brace elision: CWG does not like this; it feels like an accidental feature.
   Had we designed it from scratch, we would never have let round parens elide
   braces.
 * Order of initialization: round parens suddenly have strong ordering
   guarantees. Until now, the universal rule has bee that turning an
   aggregate into a class-with-constructors, you weaken the argument evaluation
   ordering guarantees.
 * Jens: we should be careful with features we accidentally import from braces
   that we don't actually want for round parens.
 * Mike: Sounds like we really want to take the approach of as-if-synthesizing-a-constructor
   (but still retaining aggregateness). Jason: member-initializer/constructor-call model
   rather than list-initializer model. Hubert: Constructors behave differently w.r.t.
   exceptions and temporaries.
 * Lifetime extension works differently: braces extend temporary lifetimes, parens don't.
   Another aspect where we want different behaviour, and not accidentally pull in the
   brace behaviour.
 * It matters where the full-expression ends for function-style casts "A(x, y, z)".

 *** Round 2 (Thursday) ***

 * Using the invented constructor A(x_1, ..., x_k) is problematic, since we'd need to
   make it so that the expressions x_i are not evaluated twice. At this point it's
   simpler to just go back to saying directly that the aggregate elements e_i are
   copy-initialized from the x_i.
 * Core now feels that if lifetime extension of references occurs because of this, so
   be it. We won't create an exception to disable lifetime extension. Moreover,
   default member initializers may actually *depend* on lifetime extension (e.g. by
   referring to a previous aggregate element).
 * This means that changing an aggregate to a non-aggregate class-with-constructor
   can change lifetime extension behaviour of the A(x, y, z) syntax. Core feels that
   the onus is on the library maintainer who is making that change to ensure that it
   does not break uses.
 * Richard: We eventually want to teach that "aggregate initialization is just like
   invoking a made-up constructor". That means that we want "A a(c);" to be aggregate
   initialization in the example below:

     struct A;
     struct C { operator A(); };
     struct A { C c; };

     C c;
     A a(c);         // want aggr. init., not conversion from c. Or do we?
     A a = c;        // converts from c
     A a{c};         // aggr. init (in C++17)


     A f(C c) {
       return c;      // convert or aggr. init?    Answer: convert
       return A(c);   // aggr. init
     }

     S f() { return S(1, 2, 3); }
-->

</body>
</html>


<!--

Extend lifetimes of temporaries?
SF F  N  A SA
 1 0 21 11  1

Should evaluation occur in-order?
SF  F  N A SA
 5 12 10 7  1

Make aggregate initialization preferable over conversions?
SF F  N  A SA
 1 2 15 11  3

Make it  behave *exactly* like a constructor, e.g. indeterminate evaluation order,
 non-extension of lifetime?
SF F  N A SA
 9 12 8 3  1

Should the constructor be non-explicit?
SF F  N A SA
 3 2 12 9  4

-->
