<html><head>
  <style type="text/css">
<style type="text/css">
	

body { color: #000000; background-color: #FFFFFF; }
ins, ins * { text-decoration:none; font-weight:bold; background-color:#A0FFA0 }
del, del * { text-decoration:line-through; background-color:#FFA0A0 }
#hidedel:checked ~ * del, #hidedel:checked ~ * del * { display:none; visibility:hidden }

p, li, blockquote, input {
    font-family: "sans", Times, serif;
    font-size: 11pt
}
h1, h2, h3 {font-family: "sans", Times, serif;}
h4 {font-family: "sans", Times, serif; margin-top:0.25em;}

p.example { margin-left: 2em; }
pre.example { margin-left: 2em; }
div.example { margin-left: 2em; }

code.extract { background-color: #F5F6A2; }
pre.extract { margin-left: 2em; background-color: #FFFFFF;
  border: 1px solid #E1E28E; font-family: "monospace"; }

p.function { }
.attribute { margin-left: 2em; }
.attribute dt { float: left; font-style: italic;
  padding-right: 1ex; }
.attribute dd { margin-left: 0em; }

blockquote.std { color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stddel { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5empadding-right: 0.5em; ; }

blockquote.stdins { 
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3; padding: 0.5em; padding-top:0; }

blockquote pre em { font-family: normal }

table { border: 1px solid black; border-spacing: 0px;
  margin-left: auto; margin-right: auto; }
th { text-align: left; vertical-align: top;
  padding-left: 0.8em; border: none; }
td { text-align: left; vertical-align: top;
  padding-left: 0.8em; border: none; }
  

ul { list-style-type: none; }
a { text-decoration: none; }

ul > li:before {
	content: "\2014";
	position: absolute;
	margin-left: -1.5em; 
}


p.grammarlhs { font-style:italic; margin-bottom: 0; margin-top: 0em }
p.grammarrhs { font-style:italic; margin-left:8em; margin-top:0; margin-bottom: 0; text-indent:-4em }
p.grammarrrhs { font-style:italic; margin-left:12em; margin-top:0; margin-bottom: 0; text-indent:-4em }
p.grammarlhs tt { font-style:normal }
p.grammarrhs tt { font-style:normal }
p.grammarrrhs tt { font-style:normal }

  </style>
  <title>Proposal: conversions to arrays of unknown bound</title>
</head><body>
<div style="text-align: right; float: right;">
<p>ISO/IEC JTC1 SC22 WG21, Evolution Working Group<br>
P0388R0<br>
Robert Haberlach (rh633{at}cam{dot}ac.uk)<br>
2016-06-28</p>
</div>

<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/styles/idea.min.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
	
	<h2>Permit conversions to arrays of unknown bound</h2>
	<p>Permit conversions of arrays of known bound to pointers or references to arrays of unknown bound. This is analogous to evolution issue 118.<sup><a href="#EWG118">EWG118</a></sup></p>
	
	<h3>Motivation and impact</h3>
	<p>As of core issue 393,<sup><a href="#CWG393">CWG393</a></sup> function parameters can be pointers or references to arrays of unknown bound.
	 However, binding such a parameter to an array of known bound isn't permitted:</p>

<pre class="extract"><code>void f(int(&)[]);
int arr[1];

f(arr);          // Error
int(&r)[] = arr; // Error
</code></pre>
<p>This restriction is unjustified and should be removed. The practical impact of this extension is deemed insignificant; such parameters were only allowed a while ago
(with GCC not yet supporting them), and SFINAE-dependent code that is negatively influenced by this change is most certainly not existent.</p>

	<h3>Approach and decisions</h3>
	<p>The initialization of pointers to arrays of unknown bound will be allowed by introducing a corresponding pointer conversion.
	Reference initialization rules will be adjusted by modifying reference compability. Such bindings have Exact Match rank.<br>
	
	We also propose to allow list-initialization for references to arrays of unknown bound by deducing the array temporary's size. </p>
	
	<h4>Ranking of reference initialization conversions</h4>
	<p>Consider</p>
	
<pre class="extract"><code>void f(int(&)[]),      // (1)
     f(int(&)[1]),     // (2)
     f(int*);          // (3)

void h(int(*)[]),      // (a)
     h(int(*)[1]);     // (b)
</code></pre>

<p>(2) and (b) should clearly be better than (1) and (a), respectively, as the former overloads are more restricted. <br><br>

Furthermore, (3) should be equal to (1) (as it is to (2)). To maintain this ambiguity, (1) must be given Exact Match rank. We do not favor this ordering and feel that (3) is conceptually
less specialized than (2) and even (1); however, consistency is more important than fixing part of the problem for arrays of unknown bounds.<br><br>

Finally, (a) should be worse than (b), which is implied by (a) necessitating a pointer conversion in that case.</p>

<h4>Ranking of list-initialization sequences</h4>
<p>We also propose to allow list-initialization and introduce corresponding rules in overload resolution:</p>
<pre class="extract"><code>int b(int   (&&)[] );   // #1
int b(long  (&&)[] );   // #2

int b(int   (&&)[1]);   // #3
int b(long  (&&)[1]);   // #4

int b(int   (&&)[2]);   // #5

b({1});</code></pre>
<p>Here,</p>
<ul><li>#1 and #3 should rank better than both #2 and #4, as no promotion is necessitated.</li>
<li>#1 should rank worse than #3, being far less specialized.</li>
<li>#1 and #2 should rank better than #5, as the latter requires a larger array temporary.<br>
(#3 and #4 also rank better than #5 for the same reason, which has been dealt with by core issue 1307,<sup><a href="#CWG1307">CWG1307</a></sup> whose resolution this paper extends).</li></ul>
<p>For these reasons, the size of the referenced array is the primary criterion, followed by the worst performed conversion and finally the known/unknown bound tie-breaker.</p>
	
	<h3>Proposed wording</h3>
	
	
<input type="checkbox" id="hidedel">Hide deleted wording</input>
	
	<p>Create 4.10 [conv.ptr] &para;4 with the following content:</p>
	<blockquote class="stdins">A prvalue of type &ldquo;pointer to array of <tt>N</tt>  <em>cv</em> <tt>T</tt>&ldquo; can be converted to a prvalue of type
	&ldquo;pointer to array of unknown bound of <em>cv</em> <tt>T</tt>&ldquo;.
	The result is a pointer to the array.	The null pointer value is converted to the null pointer value of the destination type.</blockquote>
	
	<p>Modify 8.5.3 [dcl.init.ref] &para;4 as follows:</p>
	
	<blockquote class="std"> Given types &ldquo;<em>cv1</em> <tt>T1</tt>&ldquo; and &ldquo;<em>cv2</em> <tt>T2</tt>&ldquo;, &ldquo;<em>cv1</em> <tt>T1</tt>&ldquo;
	is reference-related to &ldquo;<em>cv2</em> <tt>T2</tt>&ldquo; if <tt>T1</tt> is the same type as <tt>T2</tt>, <del>or</del>
	<tt>T1</tt> is a base class of <tt>T2</tt> <ins>or <tt>T1</tt> is an array type of unknown bound of <tt>U</tt> and <tt>T2</tt> is an
	array type of known bound of <tt>U</tt></ins>. </blockquote>
	
	
	<p>Modify 8.5.4 [dcl.init.list] &para;(3.8) as follows:</p>
	
	<blockquote class="std">
Otherwise, if <tt>T</tt> is a reference type, a prvalue temporary <del>of the type referenced by <tt>T</tt></del> is copy-list-initialized or direct-list-initialized,
depending on the kind of initialization for the reference, and the reference is bound to that temporary.
<ins>The type of the temporary is either the type referenced by <tt>T</tt> or, if <tt>T</tt> is "array of unknown bound of <tt>U</tt>", the type "array of <tt>N U</tt>", where <tt>N</tt> is the number of elements in the initializer list.</ins></blockquote>

<!--
	Modify 13.3.3.1 [over.ics.best] &para;6 as indicated:
	<blockquote class="std">
	When the parameter has a class type and the argument expression has a derived class type,
	the implicit conversion sequence is a derived-to-base Conversion from the derived class to the base class. <ins>When the parameter is a reference to an array of unknown bound
	and the argument is an array of known bound, the implicit conversion sequence is a bound-strip Conversion.</ins>
[ <em>Note</em>: There <del>is</del><ins>are</ins> no such standard conversion<ins>s</ins>; <del>this</del> derived-to-base <ins>and bound-strip</ins> Conversion<ins>s</ins> exist<del>s</del> only in the description of
implicit conversion sequences. &mdash; <em>end note</em> ] <del>A</del> derived-to-base <ins>and bound-strip</ins> Conversion<ins>s</ins> <del>has</del><ins>have</ins> Conversion rank (13.3.3.1.1).
	</blockquote>
-->
	
<!--
	<p>Modify 13.3.3.1.4 [over.ics.ref] &para;1 as follows: </p>
	<blockquote class="std">
	When a parameter of reference type binds directly (8.5.3) to an argument expression, the implicit conversion
	sequence is the identity conversion, unless
	<ul>
		<li>the argument expression has a type that is a derived class of the
		parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion (13.3.3.1), or</li>
		<li><ins>the argument is an array of known bound and the parameter is a reference to an
		array of unknown bound, in which case the implicit conversion sequence is a bound-strip Conversion (13.3.3.1)</ins>.</li>
	</ul>
	[ <em>Example:</em>
	<pre class="example">
	struct A {};
	struct B : public A {} b;
	int f(A&);
	int f(B&);
	int i = f(b);               // calls f(B&), an exact match, rather than
	                            // f(A&), a conversion
	                            
	<ins>int g(int(&)[]);</ins>
	<ins>int g(int(&)[5]);</ins>
	<ins>int arr[5];</ins>
	<ins>int j = g(arr);</ins>             <ins>// calls g(int(&)[5]), an exact match, rather</ins>
	                            <ins>// than f(int(&)[]), a conversion</ins>
	
	</pre>	&mdash; <em>end example</em> ]
	
	If the parameter binds directly to the result of applying a conversion function to the
	argument expression, the implicit conversion sequence is a user-defined conversion sequence (13.3.3.1.2),
	with the second standard conversion sequence <del>either</del> an identity conversion <del>or</del>, <ins>unless</ins>
	<ul>
		<li><del>if</del> the conversion function returns an entity of a type that is a derived class of the parameter type,
		<ins>in which case the standard conversion sequence is</ins> a derived-to-base Conversion<ins>, or</ins></li>
		<li><ins> the conversion function returns a reference to an array of known bound and the parameter is a reference to an array of unknown bound,
		<ins>in which case the standard conversion sequence is</ins> a bound-strip Conversion</ins>.</li>
	</ul>	
	</blockquote>
-->
	
	<p>Modify 13.3.3.1.5 [over.ics.list] &para;5 as follows:</p>
	<blockquote class="std">
	Otherwise, if the parameter type is &ldquo;array of <tt>N X</tt>&ldquo; <ins>or &ldquo;array of unknown bound of <tt>X</tt>&ldquo;</ins>, if there exists an implicit conversion sequence <del>for each
element of the array from the corresponding</del> <ins>from each</ins> element of the initializer list (<del>or</del><ins>and</ins> from <tt>{}</tt> if <del>there is no such
element</del><ins> <tt>N</tt> exceeds the number of elements in the initializer list</ins>) <ins>to <tt>X</tt></ins>, the implicit conversion sequence is the worst such implicit conversion sequence.
	</blockquote>
	
	<p>Augment 13.3.3.2 [over.ics.rank] &para;(3.1) as indicated:</p>
	<blockquote class="std">
	List-initialization sequence <tt>L1</tt> is a better conversion sequence than list-initialization sequence <tt>L2</tt> if
	<ul>
	<li><tt>L1</tt> converts to <tt>std::initializer_list&lt;X&gt;</tt> for some <tt>X</tt> and <tt>L2</tt> does not, or, if not that,</li>
	<li><tt>L1</tt> converts to type &ldquo;array of <tt>N1 T</tt>&rdquo;, <tt>L2</tt> converts to type &ldquo;array of <tt>N2 T</tt>&rdquo;, and <tt>N1</tt> is smaller than <tt>N2</tt>, <ins>or if not that,</ins></li>
	<ins><li><tt>L1</tt> converts to an array of unknown bound and <tt>L2</tt> converts to type &ldquo;array of <tt>N X</tt>&ldquo;, where <tt>N</tt> is greater than the number of elements in the initializer list,</li>
</ins>
	</ul>
	even if one of the other rules in this paragraph would otherwise apply. [<em>Example:</em>&hellip;<em>&mdash; end example</em>]
	</blockquote>
	
	<p>Create 13.3.3.2 [over.ics.rank] &para;5 with the following content:</p>
	<blockquote class="stdins">
	If none of the previous rules in this section apply, two list-initialization sequences are indistiguishable except that 
	a list-initialization sequence that converts to an array of known bound is better than one that converts to an array of unknown bound.
	[<em>Example:</em>
	<pre class="example">
void f(int    (&&)[] ),    // #1
     f(double (&&)[] ),    // #2
     f(int    (&&)[2]);    // #3

f( {1} );          // Calls #1
f( {1.0} );        // Calls #2
f( {1.0, 2.0} );   // Calls #2: Identity conversion is better than floating-integral conversion
f( {1, 2} );       // Calls #3: Converting to array of known bound is better
</pre>
	<em>&mdash; end example</em>]
	</blockquote>
	
<!--
	Add "bound-strip" to the Index in [xref], unter "conversion" (similar to derived-to-base).
-->
	
	<h3>Acknowledgments</h3>
	<p>The author would like to thank David Krauss for guidance and support.</p>
	
	<h3>References</h3>
<p>[<a id="EWG118">EWG118</a>] &ldquo;[tiny] Allow conversion from pointer to array of known bound to pointer to array of unknown bound&ldquo;: <a href="http://wg21.link/ewg118">wg21.link/ewg118</a></p>
<p>[<a id="CWG393">CWG393</a>] &ldquo;Pointer to array of unknown bound in template argument list in parameter&ldquo;: <a href="http://wg21.link/cwg393">wg21.link/cwg393</a></p>
<p>[<a id="CWG1307">CWG1307</a>] &ldquo;Overload resolution based on size of array <em>initializer-list</em>&ldquo;: <a href="http://wg21.link/cwg1307">wg21.link/cwg1307</a></p>
</body></html>
