<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml" lang="en-CA" xml:lang="en-CA"><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>On the non-uniform semantics of return-type-requirements</title>

<style type="text/css">
body { color: #000000; background-color: #FFFFFF; max-width: 50em; }
del, .del { text-decoration: line-through; color: #8B0040; }
ins, .ins { text-decoration: underline; color: #005100; }

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: #F5F6A2;
  border: 1px solid #E1E28E; }

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

blockquote.std, ul.std { color: #000000; background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.std del, blockquote.std .del, ul.std del, ul.std .del { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC; }
blockquote.std ins, blockquote.std .ins, ul.std ins, ul.std .ins { text-decoration: underline;
  color: #000000; background-color: #C8FFC8; }
blockquote.stddel { text-decoration: line-through;
  color: #000000; background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding-left: 0.5em; padding-right: 0.5em; }
blockquote.stdins { text-decoration: none;
  color: #000000; background-color: #C8FFC8;
  border: 1px solid #B3EBB3;
  padding-left: 0.5em; padding-right: 0.5em; }

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; }

table.table { border-spacing: 2px; border-collapse: separate; }
.table * th, .table * td { border: 1px solid black; }

table.frontmatter { border: 0; border-spacing: 0px; border-collapse: collapse; margin: 0; width: 619px; }
.frontmatter * td, .frontmatter * th { padding: 0px; }
.frontmatter * th { font-weight: inherit; text-align: left; vertical-align: top; }

ul.dash { list-style-type: none; }
ul.dash li:before { content: '\2014'; margin-left: -1em }

span.highlight { background-color: #7FDFFF }

.nowrap { white-space: nowrap; }
.pre { white-space: pre; }

pre { font-family: inherit; }

.subtitle { font-size: 80%; }

#xins1:checked ~ * ins { display: none; visibility: hidden }
#xdel1:checked ~ * del { display: none; visibility: hidden }
#xins2:checked ~ * ins { display: none; visibility: hidden }
#xdel2:checked ~ * del { display: none; visibility: hidden }

code.prettyprint { background-color: #F1F1F1; border-width: 1px; border-style: none dotted; border-color: #787878; padding: 0 0.25em 0 0.25em; white-space: nowrap; }
span.prettyprint { background-color: #F1F1F1; border-width: 1px; border-style: none dotted; border-color: #787878; padding: 0 0.25em 0 0.25em; white-space: nowrap; }
</style>

<script type="text/javascript" src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
</head>

<body>
<h1>On the non-uniform semantics of <i>return-type-requirement</i>s</h1>
<table class="frontmatter"><tbody>
    <tr>
        <th>Document number:</th>
        <td>P1452R2</td>
    </tr>
    <tr>
        <th>Date:</th>
        <td>2019-07-18</td>
    </tr>
    <tr>
        <th>Project:</th>
        <td>ISO/IEC JTC 1/SC 22/WG 21/C++</td>
    </tr>
    <tr>
        <th>Audience subgroup:</th>
        <td>Core, LWG</td>
    </tr>
    <tr>
        <th>Revises:</th>
        <td>P1452R1</td>
    </tr>
    <tr>
        <th>Reply-to:</th>
        <td><span class="nowrap">Hubert S.K. Tong</span> &lt;<a href="mailto:hubert.reinterpretcast@gmail.com">hubert.reinterpretcast@gmail.com</a>&gt;</td>
    </tr>
</tbody></table>

<h2>Changelog</h2>
<h3>Changes from R1</h3>
<ul><li>Added EWG discussion result.</li>
<li>Added wording implementing the direction given at EWG for review by CWG and LWG.</li>
<li>Revised the paper as requested by CWG and LWG.</li></ul>
<h3>Changes from R0</h3>
<ul><li>Updated based on presentation to EWGI at the 2019 Kona meeting.</li>
<li>Added comparative counts of <i>return-type-requirement</i>s from N4800 in terms of
<span class="prettyprint"><code>Same</code></span> versus
<span class="prettyprint"><code>ConvertibleTo</code></span>, etc.</li></ul>

<h2>Introduction</h2>
<p>What we have as a <i>return-type-requirement</i> today is a misnomer in both the syntactic and semantic sense.
The Concepts TS introduced two kinds of semantic constraints that syntactically took the form of a <i>trailing-return-type</i>:
the deduction constraint and the implicit conversion constraint.
In the time since, deduction constraints were first changed by the lack of constrained placeholders until the adoption of P1141R1 at the 2018 San Diego meeting
(becoming syntactically different from a <i>trailing-return-type</i>),
and then&#x2014;with P1084R2&#x2014;they ceased to deduce in the manner associated with return type deduction.
The syntactic space occupied by deduction constraints in the Concepts TS is now occupied by something else altogether;
however, the implicit conversion constraint lives on.
Yet the two are both <i>return-type-requirement</i>s, using the <span class="prettyprint"><code>-&gt;</code></span> token.</p>

<p>The inconsistency between the uses of the <span class="prettyprint"><code>-&gt;</code></span> token in the same context seems unfortunate; and
the <i>trailing-return-type</i> form of <i>return-type-requirement</i>, with its current semantics, appears to be easily replaceable.
Its presence in the language seems to be an unnecessary complication that may frustrate future extensions.</p>

<h2>A possible future: Generalized placeholder deduction</h2>
<p>One aspect of the Concepts TS that did not make the cut into C++2a is &#x201c;generalized <code>auto</code>&#x201d;. In particular, something like this:</p>
<blockquote><pre class="prettyprint language-cpp"><code
>void f(std::unique_ptr&lt;Concept auto&gt; p); //
    //                 ^^^ Constraint applied to the pointee type.</code
></pre></blockquote>
<p>would mean the same as:</p>
<blockquote><pre class="prettyprint language-cpp"><code
>template &lt;Concept T&gt; void f(std::unique_ptr&lt;T&gt; p);</code
></pre></blockquote>

<p>Let us then consider the application of &#x201c;generalized <code>auto</code>&#x201d; to <i>return-type-requirement</i>s where an analogue would look like this:</p>
<blockquote><pre class="prettyprint language-cpp"><code
>requires {
  { f() } -&gt; std::unique_ptr&lt;Concept auto&gt;; //
      // Constrain the pointee type.
}</code></pre></blockquote>

<p>and ask ourselves what the following should mean:</p>
<blockquote><pre class="prettyprint language-cpp"><code
>{ x } -&gt; Concept auto;</code></pre></blockquote>

<h2><span class="prettyprint"><code>-&gt; </code><i>Type</i></span> versus <span class="prettyprint"><code>-&gt; </code><i>Concept</i></span></h2>
<p>The <span class="prettyprint"><code>-&gt; </code><i>Type</i></span> form of <i>return-type-requirement</i> behaves consistently with the behaviour of
<code class="nowrap">return E;</code> for a function that is declared to return <i>Type</i> except that placeholder types are allowed for
<i>trailing-return-type</i>s in function declarations and not for <i>return-type-requirement</i>s.
That is, the semantics of the various <i>compound-requirement</i>s in</p>
<blockquote><pre class="prettyprint language-cpp"><code
>requires { { E } -&gt; </code><i>Type</i><code>; };
requires (void (&amp;f)(</code><i>Type</i><code>)) { f(E); };
requires { [](</code><i>Type</i><code>) {}(E) }; };
requires { { E } -&gt; ConvertibleTo&lt;</code><i>Type</i><code>&gt;; };</code
></pre></blockquote>
<p>are roughly the same, with the first two being equivalent. The last form is less aware of the context in terms of access checking, null pointer conversion, and
other cases where perfect forwarding is less-than-perfect. It also requires explicit conversion to be possible, and not only implicit conversion.
Both the first and the last forms are used by the library in N4800, the pre-San Diego working draft (with five instances of the first form and nine of the last form).
Note, however, that
<span class="prettyprint"><code>-&gt; Same&lt;</code><i>Type</i><code>&gt;</code></span>
is more common at forty instances.</p>

<p>In contrast to <span class="prettyprint"><code>-&gt; </code><i>Type</i></span>,
the <span class="prettyprint"><code>-&gt; </code><i>Concept</i></span> form of <i>return-type-requirement</i> most notably does not use a type after
the <span class="prettyprint"><code>-&gt;</code></span> token, but is instead one of the places where a concept name has a special meaning.
It also deduces in a manner different from either of <span class="prettyprint"><i>Concept</i><code> auto</code></span> or
<span class="prettyprint"><i>Concept</i><code> decltype(auto)</code></span> would for a function whose declared return type contains such a placeholder type,
and it does not involve a check for convertibility.</p>

<h2><span class="prettyprint"><code>-&gt; </code><i>Concept</i><code> auto</code></span> is (syntactically)
<span class="prettyprint"><code>-&gt; </code><i>Type</i></span></h2>
<p>We now come back to the question from earlier:</p>
<blockquote><pre class="prettyprint language-cpp"><code
>{ x } -&gt; Concept auto; </code><i>// What should this mean?</i
></pre></blockquote>

<p>Maybe (with <code>decltype((x))</code> being <code>int &amp;</code>):</p>
<blockquote><pre class="prettyprint language-cpp"><code
>{ x } -&gt; Concept; </code><i>// </i><code>Concept&lt;int &amp;&gt;</code><i> is satisfied.</i
></pre></blockquote>

<p>or, maybe:</p>
<blockquote><pre class="prettyprint language-cpp"><code
>auto f() -&gt; Concept auto { return x; } </code><i>// </i><code>Concept&lt;int&gt;</code><i>; no "</i><code>&amp;</code><i>" (!)</i
></pre></blockquote>

<p>Extending the current <span class="prettyprint"><code>-&gt; </code><i>Type</i></span> case to allow placeholder types would leave us with a problem where the extension
of the current semantics would lead to a difference in the meaning of the first two <i>compound-requirement</i>s in</p>
<blockquote><pre class="prettyprint language-cpp"><code
>requires {
  { E } -&gt; </code><i>Concept</i><code>;
  { E } -&gt; </code><i>Concept</i><code> auto;
  { [](</code><i>Concept</i><code> auto) {}(E) };
};</code></pre></blockquote>
<p>However, we note that the third <i>compound-requirement</i> already expresses a deduction constraint in the TS style (except that the TS wording causes
access checking, etc. to be ignored).
It would seem that extending from the current semantics of
<span class="prettyprint"><code>-&gt; </code><i>Type</i></span> <i>return-type-requirement</i>s is not very profitable.</p>

<h2><i>Concept</i><code> auto</code> with a different precedent</h2>
<p>Given:</p>
<blockquote><pre class="prettyprint language-cpp"><code
>void g(Concept auto);</code></pre></blockquote>

<p>Deduction does not only happen through deducing template arguments from a function call (akin to the current
<span class="prettyprint"><code>-&gt; </code><i>Type</i></span> deduction).
It may also happen through deducing template arguments from a function declaration, e.g.,</p>
<blockquote><pre class="prettyprint language-cpp"><code
>class A {
  static int x;
  friend void ::g(decltype((x))); </code><i
>// Would deduce </i><code>int &amp;</code><i>.</i><code>
};</code></pre></blockquote>

<p>This latter form of deduction (deducing from a type as opposed to deducing from an expression) is a possible interpretation of the change to
<span class="prettyprint"><code>-&gt; </code><i>Concept</i></span>
adopted through P1084. This can also be seen as the difference between requiring convertibility and requiring sameness.
Through these characterizations, we can make the case that <span class="prettyprint"><code>-&gt; </code><i>Type</i></span>
does not have to retain the same semantics as return type deduction.</p>

<h2>Possibility for a more powerful <span class="prettyprint"><code>-&gt; </code><i>Type</i></span> (recap)</h2>
<p>Today&#x2019;s placeholder types are limited in context; however, the Concepts TS allowed deduction constraints like</p>
<blockquote><pre class="prettyprint language-cpp"><code
>-&gt; std::vector&lt;Boolean&gt;</code></pre></blockquote>
<p>through &#x201c;generalized <code>auto</code>&#x201d;.</p>

<p>We note that this sort of &#x201c;type pattern&#x201d; is expressed in the language as a type.
Thus, if we retain <span class="prettyprint"><code>-&gt; </code><i>Type</i></span> with its current semantics,
we will not gain the benefit of applying P1084 to such cases if we were to adopt them into the language.
That <span class="prettyprint"><code>-&gt; </code><i>Concept</i></span> and
<span class="prettyprint"><code>-&gt; </code><i>Concept</i><code> auto</code></span>
would have different semantics would be highly unfortunate, as will having
<span class="prettyprint"><code>-&gt; </code><i>Type</i></span>
behave rather differently depending on whether a placeholder is present or not.</p>

<p>We also note that <span class="prettyprint"><i>Concept</i><code> auto</code></span>
already has the ability to take on semantics that behave more like
<span class="prettyprint"><i>Concept</i></span> in
<span class="prettyprint"><code>-&gt; </code><i>Concept</i></span>.
That is, we are free (at this time) to make it such that
<span class="prettyprint"><code>-&gt; </code><i>Type</i></span> has semantics matching that of <span class="prettyprint"><code>-&gt; Same&lt;</code><i>Type</i><code>&gt;</code></span>,
by far the most commonly used semantic in N4800, by applying deduction from a type as opposed to deduction from an expression.
Benefits would be that
<span class="prettyprint"><code>-&gt; </code><i>Concept</i><code> auto</code></span> would work like
<span class="prettyprint"><code>-&gt; </code><i>Concept</i></span> does in N4800, and that replacing a concrete type in a
<i>return-type-requirement</i> with a concept that the type models would not cause the <i>compound-requirement</i> to reject previously accepted cases.</p>

<h2>Proposal for C++20: remove <span class="prettyprint"><code>-&gt; </code><i>Type</i></span></h2>
<p>The <span class="prettyprint"><code>-&gt; </code><i>Type</i></span> form of <i>return-type-requirement</i>
is underpowered and does not bring additional expressiveness to the language.
It is on the wrong side of the split between <code>ConvertibleTo</code> and <code>Same</code> as used with <i>compound-requirement</i>s in N4800, and
it introduces complications for future extensions; therefore, it is proposed that the <i>trailing-return-type</i> form of <i>return-type-requirement</i>
be removed. At the same time, it is proposed that <i>trailing-type-requirement</i> is a more appropriate name.</p>

<h2>EWG discussion result</h2>
<p>The paper was presented at the 2019 Cologne meeting. Certain members of EWG indicated that the
<span class="prettyprint"><code>Same&lt;</code><i>Type</i><code>&gt;</code></span> semantics could be adopted as an alternative to removing the <i>trailing-return-type</i>
form of <i>return-type-requirement</i>.
Two polls were taken, the first to perform the removal as proposed by the paper presented, and the second to adopt the semantics of <span class="prettyprint"><code>Same</code></span>.
The first poll gained consensus, and had more consensus than the second poll.</p>

<h2>CWG discussion result</h2>
<p>CWG considered the whether a feature-test macro should be added or modified based on this paper.
The consensus of CWG was that the primary value of a feature test macro would come from the ability to write code that can benefit from using the feature conditionally and can reasonably maintain similar semantics in the alternative. In the case of the feature in question, using the feature conditionally is disadvantageous in comparison to simply using an alternative.</p>

<h2>Proposed wording</h2>
<p>Changes are relative to N4820.</p>
<p>In subclause 7.5.7 [expr.prim.req], modify the example in paragraph 3:</p>
<blockquote class="std"><p>[<i>Example</i>: A common use of <i>require-expression</i>s is to define requirements in concepts such as the one below:</p>
<pre class="example prettyprint"><code
>template&lt;typename T&gt;
concept R = requires (T i) {
    typename T::type;
    {*i} -&gt; <ins>ConvertibleTo&lt;</ins>const typename T::type&amp;<ins>&gt;</ins>;
  };</code></pre>
<p>&#x2026; &#x2014;<i>end example</i>]</p></blockquote>

<p>In subclause 7.5.7.3 [expr.prim.req.compound], remove from the grammar:</p>
<blockquote class="std"><dl><dt
><i>return-type-requirement</i>:</dt
><dd><del><i>trailing-return-type</i></del><br
/><code>-&gt;</code> <i>type-constraint</i></dd
></dl></blockquote>

<p>In subclause 7.5.7.3 [expr.prim.req.compound], modify in paragraph 1:</p>
<blockquote class="std"><ul><li>If the <i>return-type-requirement</i> is present, then:<ul>
<li>Substitution of template arguments (if any) into the <i>return-type-requirement</i> is performed.</li>
<li class="del">If the <i>return-type-requirement</i> is a <i>trailing-return-type</i> ([dcl.decl]), <code>E</code> is implicitly convertible to the type
named by the <i>trailing-return-type</i>. If conversion fails, the enclosing <i>requires-expression</i> is <code>false</code>.</li>
<li><del>If the <i>return-type-requirement</i> is of the form <code>-&gt; </code><i>type-constraint</i>, then the </del><ins>The </ins>contextually-determined
type being constrained<ins> by the <i>type-constraint</i></ins> is <code>decltype((E))</code>. The immediately-declared constraint ([temp]) of <code>decltype((E))</code> shall be satisfied.
[<i>Example</i>: &#x2026; &#x2014;<i>end example</i>]</li></ul></li></ul></blockquote>

<p>In subclause 7.5.7.3 [expr.prim.req.compound], modify the example in paragraph 2:</p>
<blockquote class="std"><p>[<i>Example</i>: &#x2026;</p>
<pre class="example prettyprint"><code
>template&lt;typename T&gt; concept C2 = requires(T x) {
  {*x} -&gt; <ins>Same&lt;</ins>typename T::inner<ins>&gt;</ins>;
};</code></pre>
<p>The <i>compound-requirement</i> in <code>C2</code> requires that <code>*x</code> is a valid expression, that <code>typename T::inner</code> is a valid type,
and that<del> <code>*x</code> is implicitly convertible to <code>typename T::inner</code></del><ins
> <code>Same&lt;decltype((*x)), typename T::inner&gt;</code> is satisfied</ins>.
&#x2026; &#x2014;<i>end example</i>]</p></blockquote>

<p>In subclause 13.6.8 [temp.concept], modify the example in paragraph 2:</p>
<blockquote class="std"><p>A <i>concept-definition</i> declares a concept. Its identifier becomes a <i>concept-name</i> referring to that concept within its scope.
[<i>Example</i>:</p>
<pre class="example prettyprint"><code
>template&lt;typename T&gt;
concept C = requires(T x) {
  { x == x } -&gt; <ins>ConvertibleTo&lt;</ins>bool<ins>&gt;</ins>;
};</code></pre>
<p>&#x2026; &#x2014;<i>end example</i>]</p></blockquote>

<p>In subclause 23.3.2.3 [iterator.traits], modify in paragraph 2:</p>
<blockquote class="std"><pre class="prettyprint"><code
>template&lt;class I&gt;
concept </code><i>cpp17-forward-iterator</i><code> =
  </code><i>cpp17-input-iterator</i><code>&lt;I&gt; &amp;&amp; Constructible&lt;I&gt; &amp;&amp;
  is_lvalue_reference_v&lt;iter_reference_t&lt;I&gt;&gt; &amp;&amp;
  Same&lt;remove_cvref_t&lt;iter_reference_t&lt;I&gt;&gt;, typename readable_traits&lt;I&gt;::value_type&gt; &amp;&amp;
  requires(I i) {
    { i++ } -&gt; <ins>ConvertibleTo&lt;</ins>const I&amp;<ins>&gt;</ins>;
    { *i++ } -&gt; Same&lt;iter_reference_t&lt;I&gt;&gt;;
  };

template&lt;class I&gt;
concept </code><i>cpp17-bidirectional-iterator</i><code> =
  </code><i>cpp17-forward-iterator</i><code>&lt;I&gt; &amp;&amp; requires(I i) {
    { --i } -&gt; Same&lt;I&amp;&gt;;
    { i-- } -&gt; <ins>ConvertibleTo&lt;</ins>const I&amp;<ins>&gt;</ins>;
    { *i-- } -&gt; Same&lt;iter_reference_t&lt;I&gt;&gt;;
  };

template&lt;class I&gt;
concept </code><i>cpp17-random-access-iterator</i><code> =
  </code><i>cpp17-bidirectional-iterator</i><code>&lt;I&gt; &amp;&amp; StrictTotallyOrdered&lt;I&gt; &amp;&amp;
  requires(I i, typename incrementable_traits&lt;I&gt;::difference_type n) {
    { i += n } -&gt; Same&lt;I&amp;&gt;;
    { i -= n } -&gt; Same&lt;I&amp;&gt;;
    { i + n } -&gt; Same&lt;I&gt;;
    { n + i } -&gt; Same&lt;I&gt;;
    { i - n } -&gt; Same&lt;I&gt;;
    { i - i } -&gt; Same&lt;decltype(n)&gt;;
    { i[n] } -&gt; <ins>ConvertibleTo&lt;</ins>iter_reference_t&lt;I&gt;<ins>&gt;</ins>;
  };</code></pre></blockquote>

<p>In subclause 24.5.3 [range.subrange], modify in paragraph 1:</p>
<blockquote class="std"><pre class="prettyprint"><code
>template&lt;class T&gt;
  concept </code><i>pair-like</i><code> = </code><i>// exposition only</i><code>
    !is_reference_v&lt;T&gt; &amp;&amp; requires(T t) {
      typename tuple_size&lt;T&gt;::type; // ensures tuple_size&lt;T&gt; is complete
      requires DerivedFrom&lt;tuple_size&lt;T&gt;, integral_constant&lt;size_t, 2&gt;&gt;;
      typename tuple_element_t&lt;0, remove_const_t&lt;T&gt;&gt;;
      typename tuple_element_t&lt;1, remove_const_t&lt;T&gt;&gt;;
      { get&lt;0&gt;(t) } -&gt; <ins>ConvertibleTo&lt;</ins>const tuple_element_t&lt;0, T&gt;&amp;<ins>&gt;</ins>;
      { get&lt;1&gt;(t) } -&gt; <ins>ConvertibleTo&lt;</ins>const tuple_element_t&lt;1, T&gt;&amp;<ins>&gt;</ins>;
    };</code></pre></blockquote>

<p>Furthermore, if additional instances of the <i>trailing-return-type</i> production of <i>return-type-requirement</i> is approved for application into the Working Draft at the same meeting as this paper is approved (e.g., P1614, &#x201c;The Mothership Has Landed: Adding <code>&lt;=&gt;</code> to the Library&#x201d;), replace said production with <code>-&gt; ConvertibleTo&lt;</code><i>Type</i><code>&gt;</code> where <i>Type</i> is the type named by the <i>trailing-return-type</i>:</p>
<blockquote class="std"><pre class="prettyprint"><code
>    { /*&#x2026;*/ } -&gt; <ins>ConvertibleTo&lt;</ins><i>Type</i><ins>&gt;</ins>;</code></pre></blockquote>

<h2>Acknowledgements</h2>
<p>The author would like to thank Walter E. Brown, Casey Carter, Paul Preney, David Stone, and any others who have been missed for their feedback on the topic of this paper.
The author would also like to thank JF Bastien, chair of the Evolution Working Group Incubator, for the opportunity to present on this topic during the February 2019 session at Kailua-Kona, Hawaii.</p>
</body></html>
