<!DOCTYPE html>
<html>
<head>
<title>[RE] Yet another</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */
/* Author: Nicolas Hery - http://nicolashery.com */
/* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */
/* Source: https://github.com/nicolahery/markdownpad-github */

/* RESET
=============================================================================*/

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
}

/* BODY
=============================================================================*/

body {
  font-family: Helvetica, arial, freesans, clean, sans-serif;
  font-size: 14px;
  line-height: 1.6;
  color: #333;
  background-color: #fff;
  padding: 20px;
  max-width: 960px;
  margin: 0 auto;
}

body>*:first-child {
  margin-top: 0 !important;
}

body>*:last-child {
  margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
  margin: 15px 0;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
  margin: 20px 0 10px;
  padding: 0;
  font-weight: bold;
  -webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
  font-size: inherit;
}

h1 {
  font-size: 28px;
  color: #000;
}

h2 {
  font-size: 24px;
  border-bottom: 1px solid #ccc;
  color: #000;
}

h3 {
  font-size: 18px;
}

h4 {
  font-size: 16px;
}

h5 {
  font-size: 14px;
}

h6 {
  color: #777;
  font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
  margin-top: 0;
  padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
  margin-top: 0;
  padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
  margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
  color: #4183C4;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
  padding-left: 30px;
}

ul li > :first-child, 
ol li > :first-child, 
ul li ul:first-of-type, 
ol li ol:first-of-type, 
ul li ol:first-of-type, 
ol li ul:first-of-type {
  margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
  margin-bottom: 0;
}

dl {
  padding: 0;
}

dl dt {
  font-size: 14px;
  font-weight: bold;
  font-style: italic;
  padding: 0;
  margin: 15px 0 5px;
}

dl dt:first-child {
  padding: 0;
}

dl dt>:first-child {
  margin-top: 0px;
}

dl dt>:last-child {
  margin-bottom: 0px;
}

dl dd {
  margin: 0 0 15px;
  padding: 0 15px;
}

dl dd>:first-child {
  margin-top: 0px;
}

dl dd>:last-child {
  margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
  font-size: 12px;
  font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
  margin: 0 0px;
  padding: 0px 0px;
  white-space: nowrap;
  border: 1px solid #eaeaea;
  background-color: #f8f8f8;
  border-radius: 3px;
}

pre>code {
  margin: 0;
  padding: 0;
  white-space: pre;
  border: none;
  background: transparent;
}

pre {
  background-color: #f8f8f8;
  border: 1px solid #ccc;
  font-size: 13px;
  line-height: 19px;
  overflow: auto;
  padding: 6px 10px;
  border-radius: 3px;
}

pre code, pre tt {
  background-color: transparent;
  border: none;
}

kbd {
    -moz-border-bottom-colors: none;
    -moz-border-left-colors: none;
    -moz-border-right-colors: none;
    -moz-border-top-colors: none;
    background-color: #DDDDDD;
    background-image: linear-gradient(#F1F1F1, #DDDDDD);
    background-repeat: repeat-x;
    border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
    border-image: none;
    border-radius: 2px 2px 2px 2px;
    border-style: solid;
    border-width: 1px;
    font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
    line-height: 10px;
    padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
  border-left: 4px solid #DDD;
  padding: 0 15px;
  color: #777;
}

blockquote>:first-child {
  margin-top: 0px;
}

blockquote>:last-child {
  margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
  clear: both;
  margin: 15px 0;
  height: 0px;
  overflow: hidden;
  border: none;
  background: transparent;
  border-bottom: 4px solid #ddd;
  padding: 0;
}

/* TABLES
=============================================================================*/

table th {
  font-weight: bold;
}

table th, table td {
  border: 1px solid #ccc;
  padding: 6px 13px;
}

table tr {
  border-top: 1px solid #ccc;
  background-color: #fff;
}

table tr:nth-child(2n) {
  background-color: #f8f8f8;
}

/* IMAGES
=============================================================================*/

img {
  max-width: 100%
}
</style>
</head>
<body>
<p>Document number: P1324R0<br />
Date: 2018-10-12<br />
Audience: EWG<br />
Reply-To: Mihail Naydenov &lt;mihailnajdenov at gmail dot com&gt;</p>
<hr />
<p><h1 align='center'>RE: Yet another approach for constrained declarations</h1></p>
<h2>Abstract</h2>
<p>This proposal is direct continuation, a &quot;reply&quot;, to <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1141r0.html">Yet another approach for constrained declarations (P1141R0)</a>.<br />
It proposes to go &quot;one step further&quot; and allow specifying a type in the place of <code>auto</code> in all constrained declarations, suggested by P1141R0. In other words  <code>void sort(Sortable auto&amp; c);</code> becomes <code>void sort(Sortable S&amp; c);</code> and as a result the specified type is introduced in the current scope.</p>
<h2>Summary</h2>
<p>This proposal is a pure extension, not an alternative or critique of P1141R0.<br />
In a nutshell, allow</p>
<pre><code class="language-cpp">void f(Sortable auto x);
Sortable auto f(); 
Sortable auto x = f(); 
template &lt;Sortable auto N&gt; void f();
</code></pre>
<p>to also be written as</p>
<pre><code class="language-cpp">void f(Sortable S x);
Sortable S f(); 
Sortable S x = f(); 
template &lt;Sortable S N&gt; void f();
</code></pre>
<p>Where <code>S</code> will be equivalent to a call to <code>decltype</code>, given the original P1141R0 declaration, or not using the terse form at all:</p>
<table style="width:100%;"><tr style="vertical-align:top;">
<td><code><pre>
void f(Sortable auto&& x)
{
  using S = decltype(x);
  // use S
}
template&lt;Sortable S&gt; void f(S&& x)
{
  // use S
}
</pre></code></td>
<td><code><pre>
void f(Sortable S&& x)
{
  // use S
}
</pre></code></td>
</tr></table>
<h2>Motivation</h2>
<p>The main motivation is explored in many other papers, like for example <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p0745r0.pdf">Concepts in-place syntax (P0745R0)</a>.<br />
It basically boils down to the fact, it is often just too convenient to have the type be known as it makes the already verbose generic code slightly less so:</p>
<p><code>auto f(Concept auto&amp;&amp; x) { return something(std::forward&lt;decltype(x)&gt;(x)); }</code>, becomes<br />
<code>auto f(Concept T&amp;&amp; x) { return something(std::forward&lt;T&gt;(x)); }</code></p>
<p><code>[](Number auto x, decltype(x) y) { }</code>, becomes<br />
<code>[](Number N x, N y) { }</code></p>
<p>And sometimes it is even impossible to create a declaration using the terse form alone:</p>
<p><code>Concept auto f(Number auto a, AnotherConcept&lt;/*?decltype(return)?*/&gt; auto b); //&lt; impossible</code><br />
<code>Concept T f(Number N a, AnotherConcept&lt;T&gt; U b); //&lt; OK</code></p>
<h3>Why this syntax</h3>
<h4>Preserving an established mental image</h4>
<p>The fact that we are dealing with types in their natural form is big advantage in terms of readability and expressiveness.<br />
Compared to P0745R0, we are not introducing additional visual clutter and new constructs to mentally parse and remember.</p>
<table style="width:100%;"><tr style="vertical-align:top;">
<td><code><pre>
void f(Concept{A}&& a, Concept{B}&& b);
</pre></code></td>
<td><code><pre>
void f(Concept A&& a, Concept B&& b);
</pre></code></td>
</tr></table>
<p>Compared to the original constrained <code>auto</code> proposal, we are not only gaining a declared type, but we also keep the declaration familiar-yet-different to standard declarations, so much so that even <em>unconstrained</em> declaration are better served.</p>
<table style="width:100%;">
<tr style="vertical-align:top;">
<td><code><pre>
void f(Concept auto&& frwref, C&& rvalue);
</pre></code></td>
<td><code><pre>
void f(Concept A&& frwref, C&& rvalue);
</pre></code></td>
</tr>
<tr style="vertical-align:top;">
<td><code><pre>
void f(auto& a, auto& b);
</pre></code></td>
<td><code><pre>
void f(Any T& a, Any U& b); //< explicit and expressive
</pre></code></td>
</tr>
</table>
<p>In the unconstrained example, the code is also ready to be &quot;upgraded&quot; to using a more constraining concept without any loss of clarity, visual similarity or the need of additional declarations and/or expressions.<br />
Not only that, the developer can track uses of &quot;loose typing&quot; by searching for all uses of the <code>Any</code> concept.</p>
<p>Notice also how the code is much more familiar to the established <code>template&lt;class T, class U&gt; void f(T&amp; a, U&amp; b);</code>, <em>both</em> by the fact we have named types <em>and</em> the fact we actually can use a custom, one letter name - something that would be lost if we were allowed to write the tersest form <code>void f(Any&amp; a, Any&amp; b); //&lt; which any? std::any or the Any concept?</code></p>
<h4>Preserving established declaration rules</h4>
<p>Consider what an <code>int n</code> states, read right to left.<br />
<em>&quot;An object named 'n' of type integer.&quot;</em><br />
But what is a type here? A type is representation in memory, technically, but a <em>constraint</em> semantically - the value of an int object can only be in certain range and only whole numbers. One can say, the value of a variable is constrained by its type - in a way, we have been writing constrains for decades, constrains on values. Let's rephrase the above with that in mind:<br />
<em>&quot;Object named 'n', that can have [only] values, belonging to the set of the int type.&quot;</em><br />
Why should constrains on types be expressed much differently?<br />
Consider now <code>Number Num n</code>:<br />
<em>&quot;Object named 'n', that can have [only] values, belonging to the set named Num, Num can [only] be a type, belonging to the set of the Numbers concept.&quot;</em><br />
As You can see, we are not inventing anything, we are just recursively applying a constraint, right to left, as we always did. In the case of constrained <code>auto</code>, we are simply omitting the name, effectively stating, we don't needed it - <code>Number auto n</code>.</p>
<blockquote>
<p>Sidenote, there are proposals, advertising the possibility to be able to omit the variable name. Using the syntax from <a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1110r0.html">P1110R0</a>, we can have fully unnamed, fully unconstrained declaration - <code>auto __</code> - alongside the fully named, fully constrained declaration we just described, <em>or</em> any combination b/w named/unnamed variable, named/unnamed type, constrained/unconstrained type and constrained/unconstrained variable.</p>
</blockquote>
<h4>Preserving established relationship b/w <code>auto</code> and a type name</h4>
<p>It must be pointed out, <code>auto</code> already stands-in for an omitted type! At the moment in all, but one case (structured bindings), if we replace <code>auto</code> with a type we end up with a valid declaration, the meaning might change, but the declaration will be valid. This means the user already associates <code>auto</code> with a &quot;type stand-in&quot;, <em>even if</em> the declaration meaning changes by the substituting one with the other.<br />
There is no reason not to continue this relationship - if the user sees an <code>auto</code>, he <em>should</em> be able to write a type name in its place. What this name represents will be new (a name introduction), but the context is also new, besides we don't stride <em>too</em> much away from the established usage..</p>
<h4>&quot;OK, but still two declarations in one expression, this is madness!&quot;</h4>
<p>Type and variable declaration have always been in C++, inherited from C. And they still have their uses.</p>
<pre><code class="language-cpp">
void process(class C&amp; c);
//...
void something(other)
{
  process(other.get_c());
}
// ...
class C {...};
// ...
void process(C&amp; c)
{
  // definition
}
</code></pre>
<p>or for example</p>
<pre><code class="language-cpp">class C
{
  // ...
private:
  const class Helper* sos() const;  //&lt; 'Helper' referenced only in just that one place 
};
</code></pre>
<p>As shown, two-in-one declaration is nothing new and although the above expressions can be written separately, this does not change the fact extremely similar syntax, with de facto the same meaning (introduce a type name inline) is already here - we just reinvent it for the new era.</p>
<blockquote>
<p>In contrast to the elaborate type specifier the declaration will be limited to the current function declaration, as-if the type was declared as template argument.</p>
</blockquote>
<h4>It is actually the tersest form!</h4>
<p><code>auto copy(InputIterator auto begin, decltype(begin) end, OutputIterator auto out) -&gt; decltype(out);</code>
<code>auto copy(InputIterator{It} begin, It end, OutputIterator{OIt} out) -&gt; OIt;</code>
<code>auto copy(InputIterator It begin, It end, OutputIterator OIt out) -&gt; OIt;</code><br />
Even compared to the original terse syntax<br />
<code>auto copy(InputIterator being, decltype(begin) end, OutputIterator out) -&gt; decltype(out);</code></p>
<p>It should be evident, enabling type name introduction in the proposed way, not only does not introduce new constructs and concepts, but serve to reinforce established ones.</p>
<h2>Not proposed, but worth mentioning</h2>
<p>Having return type name introduction, combined with trailing return type could enable us to have some interesting implications:</p>
<pre><code class="language-cpp">template&lt;class T&gt;
Container Ret function() 
  -&gt; std::map&lt;Key, T, [](const T&amp; a, const T&amp; b){ /*return result*/ }, MyAllocator&gt;
{
  Ret ret;
  // use ret with no repetition
}
</code></pre>
<p>or for example</p>
<pre><code class="language-cpp">Number Ret function(Number N a, N b) -&gt; decltype(something(x, b))
{
  Ret ret;
  // use ret with no repetition
}
</code></pre>
<p>Pretty neat, however there are two problems with that. First, lambdas do not have heading return type, and although this is solvable, the second problem is much more severe - we might want to have two different return types, for example <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1063r0.pdf">p1063r0</a> makes use of both of them already.</p>
<h2>Related work</h2>
<p>Not proposed, but a <em>possible future extension</em>, is &quot;forward declared&quot; (and effectively late-evaluated) constrained type name.</p>
<pre><code class="language-cpp">Concept T;
T val = f();
</code></pre>
<p>This idea is explored in <a href="https://hackmd.io/s/SkyQwe47Q">Concept-defined placeholder types (P1158R0)</a></p>
<h2>Interaction with other proposals</h2>
<p>The <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1157r0.html">Multi-argument constrained-parameter (P1157R0)</a> proposal suggest a multi-type constraint in the form</p>
<pre><code class="language-cpp">template&lt;class A, class B&gt; concept Duo = ...;
template&lt;Duo T U&gt;
void f(T t, U u) {}
</code></pre>
<p>as an alternative to the introducer syntax (as described in <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0694r0.pdf">Function declarations using concepts (P0694r0 )</a>).</p>
<p>Sadly, this collides with the current proposal as this syntax would mean &quot;value U of type T, constrained by a concept Duo&quot; (and Duo will have to be one template argument concept). There is no resolution to the issue - it will have to be one or the other, though it could be argued having <code>SomeConcept A B</code> and <code>OtherConcept auto C</code> mean radically different things might be confusing, because, as said, <code>auto</code> in general is a stand-in for a type - the user might expect that to be the case here as well!</p>
<h2>Conclusion</h2>
<p>Allowing concepts to introduce the type they constrain will radically change the the way we write generic code. Doing it so with effectively zero new constructs, reusing established practices, will ease the adoption of the terse form as the preferred one, possibly even for unconstrained cases.</p>

</body>
</html>
<!-- This document was created with MarkdownPad, the Markdown editor for Windows (http://markdownpad.com) -->
