<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="pandoc" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <title>P2355R2: Postfix fold expressions</title>
  <style type="text/css">
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
  </style>
  <style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; position: absolute; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
  { position: relative; }
pre.numberSource a.sourceLine:empty
  { position: absolute; }
pre.numberSource a.sourceLine::before
  { content: attr(data-line-number);
    position: absolute; left: -5em; text-align: right; vertical-align: baseline;
    border: none; pointer-events: all;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
    color: #aaaaaa;
  }
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
div.sourceCode
  {  }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
  </style>
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  <style type="text/css">
  div.del, section.del { background: #fcd; }
  div.ins, section.ins { background: #bfa; }
  .mv { background: #ddf; }
  s, .del { background: #ff8888; margin-right: 0.15ch; }
  u, .ins { background: #88ff88; }
  /* from https://stackoverflow.com/a/32456613 */
  div > blockquote, body > blockquote {
      display: list-item;
      list-style-type: "- ";
  }
  /* With a 3 em gutter and two columns, ANSI letter is 127 characters wide. */
  pre {
  		margin-left: 1.2em;
  }
  .tony {
    border-collapse: collapse;
  }
  .tony > tbody > tr {
    vertical-align: top;
  }
  tr.hr, tr.hr {
    border-bottom: thin solid #60a0b0;  /* relies on collapse */
  }
  </style>
</head>
<body>
<header>
<h1 class="title">P2355R2: Postfix fold expressions<!-- -*- c++-md -*- --></h1>
</header>
<p><em>Audience</em>: EWG<br />
S. Davis Herring &lt;<a href="mailto:herring@lanl.gov">herring@lanl.gov</a>&gt;<br />
March 20, 2024</p>
<h1 id="history">History</h1>
<p>Since <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2355r1.html">r1</a>:</p>
<ul>
<li>Rebased onto N4971, accounting for P2128</li>
<li>Discussed additional syntax for folding over a function</li>
<li>Clarified commentary</li>
</ul>
<p>Since <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2355r0.html">r0</a>:</p>
<ul>
<li>Prohibited inconsistent folds like <code>(x[...[abc]])</code></li>
<li>Fixed syntax in <code>index</code> example</li>
<li>Used <em>initializer-clause</em> instead of redundant <em>assign-or-braced-init-list</em></li>
</ul>
<h1 id="introduction">Introduction</h1>
<p>Fold expressions work with binary operators, but not with unary operators: you can write <code>!!…!!x</code>, but there’s still only one <code>x</code>. However, there are other kinds of operators to which they might apply. In particular, there are several plausible use cases for the postfix operators <code>[]</code> and <code>()</code> (function call). This paper proposes extending the <em>fold-expression</em> syntax to support these two operators. The rationale for the syntactical structure is also presented.</p>
<h1 id="syntax">Syntax</h1>
<p>The appropriate syntax may not be immediately obvious, but it can be constructed by analogy to the binary operator case. In particular, the subscripting operator is almost an ordinary binary operator already. (Infamously, the built-in operator is commutative: <code>1[&quot;$?&quot;]</code> has the same meaning as <code>&quot;$?&quot;[1]</code>.) Consider how it would be supported as a binary operator <code>@</code> (to which we will not ascribe an associativity): if <code>x @ a</code> is equivalent to <code>x[a]</code>, then <code>x[a][b][c]</code> is equivalent to <code>((x @ a) @ b) @ c</code>, which is the result of the binary left fold <code>(x @ ... @ abc)</code>. Bearing in mind the implied grouping, that fold suggests the syntax</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb1-1" data-line-number="1">(x[...][abc])</a></code></pre></div>
<p>for the case of recursive indexing.</p>
<p>Similarly, <code>(xyz[...[a]])</code> or <code>(xyz @ ... @ a)</code> means <code>x @ (y @ (z @ a))</code> or <code>x[y[z[a]]]</code>: a lookup with a sequence of indirections. Note the corresponding nesting in the fold-expression form. Furthermore, <code>(xyz[...])</code> is the unary right fold <code>(xyz @ ...)</code>, which is <code>x[y[z]]</code>, and the unary left fold <code>(...[xyz])</code> means <code>x[y][z]</code>; these have somewhat narrower applicability, since elements of the same pack must be usable both as containers and as indices. As <em>postfix-expression</em>s have the highest precedence, parentheses are strictly required only for the unary cases, but it is prudent to require them in all cases for consistency.</p>
<p>The corresponding cases for the call operator are obvious: a left fold applies each result to the next argument as a function (in a fashion similar to method chaining), while a right fold composes functions in a pack.</p>
<p>Of course, these operators are not strictly binary in that their right operand need not be a single expression. However, the generalization is straightforward: the right operand of a fold can be an entire (possibly empty) argument list. A unary fold must use the expansion of its operand on the left of the operator at least once, so only binary folds may be used:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb2-1" data-line-number="1">(f(...)(abc,x))    <span class="co">// f(a,x)(b,x)(c,x)</span></a>
<a class="sourceLine" id="cb2-2" data-line-number="2">(f(...)(abc,xyz))  <span class="co">// f(a,x)(b,y)(c,z)</span></a>
<a class="sourceLine" id="cb2-3" data-line-number="3">(fgh(...(a,x)))    <span class="co">// f(g(h(a,x)))</span></a>
<a class="sourceLine" id="cb2-4" data-line-number="4">(a[...][{ijk,<span class="dv">0</span>}])  <span class="co">// a[{i,0}][{j,0}][{k,0}]</span></a></code></pre></div>
<p>Were it desired, even the cast operators would work in just the binary right fold case:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb3-1" data-line-number="1">(<span class="kw">static_cast</span>&lt;TUV&gt;(<span class="kw">static_cast</span>&lt;...&gt;(a)))  <span class="co">// static_cast&lt;T&gt;(static_cast&lt;U&gt;(static_cast&lt;V&gt;(a)))</span></a>
<a class="sourceLine" id="cb3-2" data-line-number="2">(TUV{...{a,x}})                          <span class="co">// T{U{V{a,x</span><span class="re">}}}</span></a>
<a class="sourceLine" id="cb3-3" data-line-number="3">((TUV)(...)a)                            <span class="co">// (T)(U)(V)a</span></a></code></pre></div>
<p>Placement new would similarly support just the binary left fold:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb4-1" data-line-number="1">(<span class="kw">new</span> (<span class="kw">new</span> (x) ...) TUV)                  <span class="co">// new (new (new (x) T) U) V</span></a>
<a class="sourceLine" id="cb4-2" data-line-number="2">(<span class="kw">new</span> (<span class="kw">new</span> (x) ...) T(abc,y))             <span class="co">// new (new (new (x) T(a,y)) T(b,y)) T(c,y)</span></a></code></pre></div>
<p>These are illustrated here for completeness and to demonstrate the generality of the approach; they are certainly not proposed.</p>
<h1 id="motivation">Motivation</h1>
<h2 id="section"><code>[]</code></h2>
<p>The syntactic investigation for this proposal was instigated by the discussion of multi-parameter subscripting operators. The notion of folding over <code>[]</code> was <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1161r2.html#alternative-syntax-for-multidimensional-subscript-expressions">explicitly mentioned</a> in proposals on the subject, and it can be used with types (like arrays and <code>std::vector</code>) that do not support multiple subscripting arguments:</p>
<table class="tony">
<tr>
<th>
C++23
</th>
<th>
</th>
<th>
this proposal
</th>
</tr>
<tr>
<td>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb5-1" data-line-number="1"><span class="co">// arr defines a multi-parameter operator[]</span></a>
<a class="sourceLine" id="cb5-2" data-line-number="2"><span class="kw">decltype</span>(<span class="kw">auto</span>) index(<span class="kw">auto</span> &amp;arr,<span class="kw">auto</span> ...ii)</a>
<a class="sourceLine" id="cb5-3" data-line-number="3">{<span class="cf">return</span> arr[ii...];}</a></code></pre></div>
</td>
<td style="width: 3em">
</td>
<td>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb6-1" data-line-number="1"><span class="co">// arr defines a C++20 proxy-based operator[]</span></a>
<a class="sourceLine" id="cb6-2" data-line-number="2"><span class="kw">decltype</span>(<span class="kw">auto</span>) index(<span class="kw">auto</span> &amp;arr,<span class="kw">auto</span> ...ii)</a>
<a class="sourceLine" id="cb6-3" data-line-number="3">{<span class="cf">return</span> (arr[...][ii]);}</a></code></pre></div>
</td>
</tr>
</table>
<p>This proposal also supports the very different right fold case.</p>
<h2 id="section-1"><code>()</code></h2>
<p>The convenience of fold expressions (especially when the successive subexpressions might have different types), combined with their restriction to operators, has led to <a href="https://stackoverflow.com/questions/27582862/fold-expressions-with-arbitrary-callable">common usage of workarounds</a> involving expressing a function as an operator defined for a type that exists purely to allow a fold. This proposal allows function objects to be used instead, reducing syntactic overhead.</p>
<table class="tony">
<tr>
<th>
C++20
</th>
<th>
</th>
<th>
this proposal
</th>
</tr>
<tr class="hr">
<td>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb7-1" data-line-number="1"><span class="kw">namespace</span> detail {</a>
<a class="sourceLine" id="cb7-2" data-line-number="2">  <span class="kw">template</span>&lt;<span class="kw">class</span> F&gt;</a>
<a class="sourceLine" id="cb7-3" data-line-number="3">  <span class="kw">struct</span> call {</a>
<a class="sourceLine" id="cb7-4" data-line-number="4">    F &amp;&amp;f;</a>
<a class="sourceLine" id="cb7-5" data-line-number="5">    <span class="kw">template</span>&lt;<span class="kw">class</span> T&gt;</a>
<a class="sourceLine" id="cb7-6" data-line-number="6">    <span class="kw">decltype</span>(<span class="kw">auto</span>) <span class="kw">operator</span>|(T &amp;&amp;t) <span class="at">const</span></a>
<a class="sourceLine" id="cb7-7" data-line-number="7">    {<span class="cf">return</span> <span class="bu">std::</span>forward&lt;F&gt;(f)(<span class="bu">std::</span>forward&lt;T&gt;(t));}</a>
<a class="sourceLine" id="cb7-8" data-line-number="8">  };</a>
<a class="sourceLine" id="cb7-9" data-line-number="9">}</a>
<a class="sourceLine" id="cb7-10" data-line-number="10"></a>
<a class="sourceLine" id="cb7-11" data-line-number="11"><span class="kw">template</span>&lt;<span class="kw">class</span> T,<span class="kw">class</span> X&gt;</a>
<a class="sourceLine" id="cb7-12" data-line-number="12"><span class="kw">decltype</span>(<span class="kw">auto</span>) nest_tuple(T &amp;&amp;t,X &amp;&amp;x) {</a>
<a class="sourceLine" id="cb7-13" data-line-number="13">  <span class="cf">return</span> <span class="bu">std::</span>apply</a>
<a class="sourceLine" id="cb7-14" data-line-number="14">    ([&amp;x]&lt;<span class="kw">class</span> ...TT&gt;(TT &amp;&amp;...tt) -&gt; <span class="kw">decltype</span>(<span class="kw">auto</span>)</a>
<a class="sourceLine" id="cb7-15" data-line-number="15">     {<span class="cf">return</span> (detail::call&lt;TT&gt;{<span class="bu">std::</span>forward&lt;TT&gt;(tt)} | ...</a>
<a class="sourceLine" id="cb7-16" data-line-number="16">       | <span class="bu">std::</span>forward&lt;X&gt;(x));},</a>
<a class="sourceLine" id="cb7-17" data-line-number="17">     <span class="bu">std::</span>forward&lt;T&gt;(t));</a>
<a class="sourceLine" id="cb7-18" data-line-number="18">}</a></code></pre></div>
</td>
<td style="width: 3em">
</td>
<td>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb8-1" data-line-number="1"><span class="kw">template</span>&lt;<span class="kw">class</span> T,<span class="kw">class</span> X&gt;</a>
<a class="sourceLine" id="cb8-2" data-line-number="2"><span class="kw">decltype</span>(<span class="kw">auto</span>) nest_tuple(T &amp;&amp;t,X &amp;&amp;x) {</a>
<a class="sourceLine" id="cb8-3" data-line-number="3">  <span class="cf">return</span> <span class="bu">std::</span>apply</a>
<a class="sourceLine" id="cb8-4" data-line-number="4">    ([&amp;x]&lt;<span class="kw">class</span> ...TT&gt;(TT &amp;&amp;...tt) -&gt; <span class="kw">decltype</span>(<span class="kw">auto</span>)</a>
<a class="sourceLine" id="cb8-5" data-line-number="5">     {<span class="cf">return</span> (<span class="bu">std::</span>forward&lt;TT&gt;(tt)(...(<span class="bu">std::</span>forward&lt;X&gt;(x))));},</a>
<a class="sourceLine" id="cb8-6" data-line-number="6">     <span class="bu">std::</span>forward&lt;T&gt;(t));</a>
<a class="sourceLine" id="cb8-7" data-line-number="7">}</a></code></pre></div>
</td>
</tr>
<tr>
<td>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb9-1" data-line-number="1"><span class="kw">namespace</span> detail {</a>
<a class="sourceLine" id="cb9-2" data-line-number="2">  <span class="kw">template</span>&lt;<span class="kw">class</span> T&gt;</a>
<a class="sourceLine" id="cb9-3" data-line-number="3">  <span class="kw">struct</span> smaller {</a>
<a class="sourceLine" id="cb9-4" data-line-number="4">    T &amp;t;</a>
<a class="sourceLine" id="cb9-5" data-line-number="5">    <span class="kw">template</span>&lt;<span class="kw">class</span> U&gt;</a>
<a class="sourceLine" id="cb9-6" data-line-number="6">    <span class="kw">auto</span>&amp; <span class="kw">operator</span>|(<span class="at">const</span> smaller&lt;U&gt; &amp;c) <span class="at">const</span> {</a>
<a class="sourceLine" id="cb9-7" data-line-number="7">      <span class="cf">if</span> <span class="kw">constexpr</span>(<span class="kw">sizeof</span>(T)&lt;<span class="kw">sizeof</span>(U)) <span class="cf">return</span> *<span class="kw">this</span>;</a>
<a class="sourceLine" id="cb9-8" data-line-number="8">      <span class="cf">else</span> <span class="cf">return</span> c;</a>
<a class="sourceLine" id="cb9-9" data-line-number="9">    }</a>
<a class="sourceLine" id="cb9-10" data-line-number="10">  };</a>
<a class="sourceLine" id="cb9-11" data-line-number="11">}</a>
<a class="sourceLine" id="cb9-12" data-line-number="12"></a>
<a class="sourceLine" id="cb9-13" data-line-number="13"><span class="kw">auto</span>&amp; smallest(<span class="at">const</span> <span class="kw">auto</span> &amp;...aa)</a>
<a class="sourceLine" id="cb9-14" data-line-number="14">{<span class="cf">return</span> (detail::smaller{aa} | ...).t;}</a></code></pre></div>
<p>or (at the cost of duplicating what could be a long signature and of requiring a great deal of inlining for efficiency)</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb10-1" data-line-number="1"><span class="kw">auto</span>&amp; smallest(<span class="at">const</span> <span class="kw">auto</span> &amp;a) {<span class="cf">return</span> a;}</a>
<a class="sourceLine" id="cb10-2" data-line-number="2"><span class="kw">auto</span>&amp; smallest(<span class="at">const</span> <span class="kw">auto</span> &amp;a,<span class="at">const</span> <span class="kw">auto</span> &amp;...aa) {</a>
<a class="sourceLine" id="cb10-3" data-line-number="3">  <span class="kw">auto</span> &amp;b=smallest(aa...);</a>
<a class="sourceLine" id="cb10-4" data-line-number="4">  <span class="cf">if</span> <span class="kw">constexpr</span>(<span class="kw">sizeof</span> a &lt; <span class="kw">sizeof</span> b) <span class="cf">return</span> a;</a>
<a class="sourceLine" id="cb10-5" data-line-number="5">  <span class="cf">else</span> <span class="cf">return</span> b;</a>
<a class="sourceLine" id="cb10-6" data-line-number="6">}</a></code></pre></div>
</td>
<td style="width: 3em">
</td>
<td>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb11-1" data-line-number="1"><span class="kw">auto</span> smallest(<span class="at">const</span> <span class="kw">auto</span> &amp;a,<span class="at">const</span> <span class="kw">auto</span> &amp;...aa) {</a>
<a class="sourceLine" id="cb11-2" data-line-number="2">  <span class="cf">return</span> ([&amp;](<span class="kw">auto</span> &amp;x) -&gt; <span class="kw">auto</span>&amp; {</a>
<a class="sourceLine" id="cb11-3" data-line-number="3">    <span class="cf">if</span> <span class="kw">constexpr</span>(<span class="kw">sizeof</span> aa &lt; <span class="kw">sizeof</span> x) <span class="cf">return</span> aa;</a>
<a class="sourceLine" id="cb11-4" data-line-number="4">    <span class="cf">else</span> <span class="cf">return</span> x;</a>
<a class="sourceLine" id="cb11-5" data-line-number="5">  }(...(a)));</a>
<a class="sourceLine" id="cb11-6" data-line-number="6">}</a></code></pre></div>
<p>Note here that the fold produces</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb12-1" data-line-number="1">ff...[<span class="dv">0</span>](ff...[<span class="dv">1</span>](...(ff...[<span class="kw">sizeof</span>...(aa)<span class="dv">-1</span>](a))))</a></code></pre></div>
<p>where <code>ff</code> is the pack of lambdas, treating <code>a</code> after <code>aa</code>; considering the lambda as a function of its capture and its actual parameter, this is</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb13-1" data-line-number="1">f(aa...[<span class="dv">0</span>],f(aa...[<span class="dv">1</span>],...f(aa...[<span class="kw">sizeof</span>...(aa)<span class="dv">-1</span>],a)))</a></code></pre></div>
</td>
</tr>
</table>
<h3 id="these-arent-the-folds-youre-looking-for">These aren’t the folds you’re looking for</h3>
<p>Of course, the usual meaning of “fold over a function” is is an expression of the form <code>f(a,f(b,f(c,d)))</code>. The above cannot directly produce such an expression, because it is a fold over <code>f</code> <em>itself</em> rather than over <code>()</code>. The <code>smallest</code> example illustrates how to assemble one anyway (given the separate <code>a</code>), and it can be generalized, but the result (treated as an opaque API) might as well be implemented with other metaprogramming:</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb14-1" data-line-number="1"><span class="kw">template</span>&lt;<span class="kw">class</span> F,<span class="kw">class</span> T,<span class="kw">class</span> ...TT&gt;</a>
<a class="sourceLine" id="cb14-2" data-line-number="2"><span class="kw">decltype</span>(<span class="kw">auto</span>) fold(F &amp;&amp;f,T &amp;&amp;t,TT &amp;&amp;...tt) {</a>
<a class="sourceLine" id="cb14-3" data-line-number="3">  <span class="cf">return</span> ([](<span class="kw">auto</span> &amp;&amp;x) -&gt; <span class="kw">decltype</span>(<span class="kw">auto</span>)</a>
<a class="sourceLine" id="cb14-4" data-line-number="4">          {<span class="cf">return</span> f(<span class="bu">std::</span>forward&lt;TT&gt;(tt),<span class="bu">std::</span>forward&lt;<span class="kw">decltype</span>(x)&gt;(x));}</a>
<a class="sourceLine" id="cb14-5" data-line-number="5">          (...(<span class="bu">std::</span>forward&lt;T&gt;(t))));</a>
<a class="sourceLine" id="cb14-6" data-line-number="6">}</a></code></pre></div>
<p>There is, however, another syntax that would support the desired folds, based on extending the syntax of a fold to operators with an arity greater than 2. The observation is that expanding a fold consists of repeatedly replacing the <code>...</code> with a copy of the expression, leaving one element of the pack behind in the outer expression. When the pack has just one element left, it is substituted for the <code>...</code> instead of another copy. In the abstract, this means that</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb15-1" data-line-number="1">a : b : ... : c : wxyz</a></code></pre></div>
<p>(for some fictitious quinary operator) expands to</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb16-1" data-line-number="1">a : b : (a : b : (a : b : w : c : x) : c : y) : c : z</a></code></pre></div>
<p>where the placement of the pack elements is simply chosen to have them in lexical order (as is true for all existing folds).</p>
<p>Applying this logic to the function-call operator, interpreted not as a binary operator (applied to <em>a function</em> and <em>an argument list</em>) but as an operator of arbitrary arity applied to a function and various arguments, suggests that the syntax</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb17-1" data-line-number="1">(f(...,abcd))</a></code></pre></div>
<p>would have the desirable expansion</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb18-1" data-line-number="1">f(f(f(a,b),c),d)</a></code></pre></div>
<p>Note that the right-fold case would be very similar to the existing <code>f(abcd...)</code> for plain pack expansion; typically such errors would be fairly obvious. The syntax would immediately support further arguments, so long as exactly one contained an unexpanded pack. Each (and <code>f</code> itself) would be evaluated in each of its appearances, which is more expressive even if it also invites inefficiency in some cases.</p>
<p>One would also want binary folds (in the fold-expression sense), both for supplying an initial value (especially for empty folds, as usual) and to support packs in more than one operand (because no level of the expansion needs exactly one extra). However, it is also more syntactically difficult: repeating the n-ary operator in the usual fashion would produce</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb19-1" data-line-number="1">(f(f(x,...),abcd))</a></code></pre></div>
<p>which would be ambiguous without the extra surrounding parentheses and requires repeating the function and verifying that it (a potentially non-trivial expression) is repeated accurately. It would be possible to supply the initial value with stripped-down syntax like</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><a class="sourceLine" id="cb20-1" data-line-number="1">(f(...(x),abcd))</a></code></pre></div>
<p>(which could directly support <code>fghi</code> as a pack as well) but then <code>x</code> appears as if it were the lone argument to some function call as well as appearing on the wrong side of <code>...</code>.</p>
<h1 id="proposal">Proposal</h1>
<p>For C++26, support unary and binary folds over the operators <code>[]</code> and <code>()</code>, with the syntax summarized below for the latter. Do not support empty unary folds for either operator for lack of an appropriate identity element. (One could argue for some sort of identity function that preserves value category for <code>()</code> (as a left identity like <code>void()</code> is for <code>,</code>), but that seems drastically inventive.)</p>
<p>No specific choice is proposed for the fold over <code>()</code> as an arbitrary-arity operator, pending EWG feedback. In any event, these changes do not affect the meaning of well-formed C++23 programs; the syntax is ungrammatical there.</p>
<table>
<tr>
<td>
</td>
<td>
Example
</td>
<td>
Meaning
</td>
</tr>
<tr>
<td>
Binary left fold
</td>
<td style="padding-right: 2em">
<code>(f(...)({abc,0},x))</code>
</td>
<td>
<code>f({a,0},x)({b,0},x)({c,0},x)</code>
</td>
</tr>
<tr>
<td>
</td>
<td>
<code>(f(...)(abc,xyz))</code>
</td>
<td>
<code>f(a,x)(b,y)(c,z)</code>
</td>
</tr>
<td style="padding-right: 2em">
Binary right fold
</td>
<td>
<code>(fgh(...({a,0},x)))</code>
</td>
<td>
<code>f(g(h({a,0},x)))</code>
</td>
</tr>
<tr>
<td>
</td>
<td>
<code>(fgh(...()))</code>
</td>
<td>
<code>f(g(h()))</code>
</tr>
<tr>
<td>
Unary left fold
</td>
<td>
<code>(...(abc))</code>
</td>
<td>
<code>a(b)(c)</code>
</td>
</tr>
<tr>
<td>
Unary right fold
</td>
<td>
<code>(abc(...))</code>
</td>
<td>
<code>a(b(c))</code>
</td>
</tr>
</table>
<h1 id="wording">Wording</h1>
<p>Relative to N4971.</p>
<h2 id="expr.prim.fold">[expr.prim.fold]</h2>
<p>Change paragraph 1:</p>
<blockquote>
<p>A fold expression performs a fold of a pack ([temp.variadic]) over a binary<u> or postfix</u> operator.</p>
<blockquote>
<p><em>fold-expression</em>:</p>
<blockquote>
<p><code>(</code> <em>cast-expression</em> <em>fold-operator</em> <code>...</code> <code>)</code><br />
<code>(</code> <code>...</code> <em>fold-operator</em> <em>cast-expression</em> <code>)</code><br />
<code>(</code> <em>cast-expression</em> <em>fold-operator</em> <code>...</code> <em>fold-operator</em> <em>cast-expression</em> <code>)</code><br />
<u><code>(</code> <em>postfix-expression</em> <code>[</code> <code>...</code> <code>]</code> <code>[</code> <em>expression-list</em><sub><em>opt</em></sub> <code>]</code> <code>)</code><br />
<code>(</code> <em>postfix-expression</em> <code>[</code> <code>...</code> <code>[</code> <em>expression-list</em><sub><em>opt</em></sub> <code>]</code> <code>]</code> <code>)</code><br />
<code>(</code> <em>postfix-expression</em> <code>[</code> <code>...</code> <code>]</code> <code>)</code><br />
<code>(</code> <code>...</code> <code>[</code> <em>assignment-expression</em> <code>]</code> <code>)</code><br />
<code>(</code> <em>postfix-expression</em> <code>(</code> <code>...</code> <code>)</code> <code>(</code> <em>expression-list</em><sub><em>opt</em></sub> <code>)</code> <code>)</code><br />
<code>(</code> <em>postfix-expression</em> <code>(</code> <code>...</code> <code>(</code> <em>expression-list</em><sub><em>opt</em></sub> <code>)</code> <code>)</code> <code>)</code><br />
<code>(</code> <em>postfix-expression</em> <code>(</code> <code>...</code> <code>)</code> <code>)</code><br />
<code>(</code> <code>...</code> <code>(</code> <em>assignment-expression</em> <code>)</code> <code>)</code></u></p>
</blockquote>
<p>[…]</p>
</blockquote>
</blockquote>
<p>Change paragraph 2:</p>
<blockquote>
<p><s>An expression of the form</s><u>A <em>fold-expression</em> that begins with</u> <code>(...</code><s> <em>op</em> <code>e)</code> where <em>op</em> is a <em>fold-operator</em></s> is called a <em>unary left fold</em>. <s>An expression of the form <code>(e</code> <em>op</em></s><u>A <em>fold-expression</em> that ends with</u> <code>...)</code><s> where <em>op</em> is a <em>fold-operator</em></s><u>, <code>[...])</code>, or <code>(...))</code></u> is called a <em>unary right fold</em>. Unary left folds and unary right folds are collectively called <em>unary folds</em>. In a unary fold, the <em>cast-expression</em><u>, <em>postfix-expression</em>, or <em>assignment-expression</em></u> shall contain an unexpanded pack ([temp.variadic]).</p>
</blockquote>
<p>Change paragraph 3:</p>
<blockquote>
<p><s>An expression of the form <code>(e1</code> <em>op1</em> <code>...</code> <em>op2</em> <code>e2)</code> where <em>op1</em> and <em>op2</em> are <em>fold-operator</em>s</s><u>Any other <em>fold-expression</em></u> is called a <em>binary fold</em>. <s>In</s><u>If</u> a binary fold<s>, <em>op1</em> and <em>op2</em> shall be the same</s><u> contains two</u> <em>fold-operator</em><s>, and either <code>e1</code> shall contain an unexpanded pack or <code>e2</code> shall</s><u>s, they shall be the same. A binary fold has two operands, each an expression, an <em>expression-list</em> or nothing, or a <em>braced-init-list</em>; exactly one of them shall</u> contain an unexpanded pack<s>, but not both</s>. If <s><code>e2</code></s><u>the second</u> contains an unexpanded pack, the expression is called a <em>binary left fold</em><u>; it shall not end with <code>)))</code> or <code>]])</code></u>. If <s><code>e1</code></s><u>the first</u> contains an unexpanded pack, the expression is called a <em>binary right fold</em><u>; it shall not be formed with <code>(...)</code> or <code>[...]</code></u>. [<em>Example</em>:</p>
<p>[…]</p>
<p>— <em>end example</em>]</p>
</blockquote>
<h2 id="temp.variadic">[temp.variadic]</h2>
<p>Change bullet (5.14):</p>
<blockquote>
<p>In a <em>fold-expression</em> ([expr.prim.fold]); the pattern is the <s><em>cast-expression</em></s><u>operand</u> that contains an unexpanded pack.</p>
</blockquote>
<p>Change paragraph 13:</p>
<blockquote>
<p>The instantiation of a <em>fold-expression</em> ([expr.prim.fold]) produces:</p>
<p>[…]</p>
<p>In each case, <em>op</em> is the <em>fold-operator</em>.<u> If there is no <em>fold-operator</em>, <em>op</em> is a notional operator that applies the subscription operator if the <em>fold-expression</em> has a <code>[</code> or the function call operator otherwise, such that <code>X</code> <em>op</em> <code>Y</code> is <code>X[Y]</code> or <code>X(Y)</code> respectively.</u></p>
<p><u>[<em>Note</em>: It is possible for <code>Y</code> to be a possibly empty expression list or a <em>braced-init-list</em>. — <em>end note</em>]</u></p>
<p>For a binary fold, <code>E</code> is generated by instantiating the <s><em>cast-expression</em></s><u>operand</u> that did not contain an unexpanded pack.</p>
<p>[…]</p>
</blockquote>
</body>
</html>
