<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-11-22" />
  <title>Structured Bindings can introduce a Pack</title>
  <style>
      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%;}
      div.csl-block{margin-left: 1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -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
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <style type="text/css">a {
color : #4183C4;
text-decoration: underline;
}
a.marginalized {
text-decoration: none;
}
a.self-link {
text-decoration: none;
}
h1#toctitle {
border-bottom: 1px solid #cccccc;
}
#TOC li {
margin-top: 1px;
margin-bottom: 1px;
}
#TOC ul>li:before { display: none; }
h3.subtitle { margin-top: -15px; }
h1:target { background-color: transparent; }
h2:target { background-color: transparent; }
h3:target { background-color: transparent; }
h4:target { background-color: transparent; }
h5:target { background-color: transparent; }
h6:target { background-color: transparent; }
code span.co { font-family: monospace; }
table tr {
background-color: white;
}
table tr:nth-child(2n) {
background-color: #f6f8fa;
}
#title-block-header > table tr:nth-child(2n) {
background-color: white;
}
td > div.sourceCode {
background-color: inherit;
}
table {
border-collapse: collapse;
}
table td, table th {
border: 1px solid #cccccc;
}
table th {
border-bottom: 1px solid black;
text-align: center;
}
table tr:first-child th {
border-top: 0;
}
table tr:last-child td {
border-bottom: 0;
}
table tr td:first-child,
table tr th:first-child {
border-left: 0;
}
table tr td:last-child,
table tr th:last-child {
border-right: 0;
}
table tbody tr:first-child td {
border-top: 1px solid black;
}
#title-block-header td { border: 0; }
@media all {
body {
margin: 2em;
}
}
@media screen and (min-width: 480px) {
body {
margin: 5em;
}
}
#refs code{padding-left: 0px; text-indent: 0px;}
:root {
--diff-ins: #C9FBC9;
--diff-strongins: #acf2bd;
--diff-del: #FFC8EB;
--diff-strongdel: #ff8888;
}
span.diffins {
background-color: var(--diff-strongins);
}
span.diffdel {
background-color: var(--diff-strongdel);
}
div.rm { text-decoration: line-through; }
div.rm code.sourceCode { text-decoration: line-through; }
div.addu, span.addu {
color: #006e28;
background-color: var(--diff-ins);
}

div.rm pre, div.add pre { background-color: #f6f8fa; }
div.addu pre { background-color: var(--diff-ins); }
div.add, div.add pre { background-color: var(--diff-ins); }
div.addu blockquote {
border-left: 4px solid #00a000;
padding: 0 15px;
color: #006e28;
text-decoration: none;
}
div.addu blockquote code.sourceCode { text-decoration: none; }
div.addu blockquote pre { text-decoration: none; }
div.addu blockquote pre code { text-decoration: none; }
div.quote {
border-left: 7px solid #ccc;
background: #f9f9f9;
margin: 1.5em 10px;
padding-left: 20px;
}
code.diff span.va { color: #000000; background-color: var(--diff-ins); }
code.diff span.st { color: #000000; background-color: var(--diff-del); }
div.std blockquote { color: #000000; background-color: #F1F1F1;
border: 1px solid #D1D1D1;
padding-left: 0.5em; padding-right: 0.5em; }
div.std.ins blockquote {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.ins > div.example {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.std div.sourceCode { background-color: inherit; margin-left: 1em; }
div.std blockquote del { text-decoration: line-through;
color: #000000; background-color: var(--diff-del);
border: none; }
code del { border: 1px solid #ECB3C7; }
span.orange {
background-color: #ffa500;
}
span.yellow {
background-color: #ffff00;
}</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Structured Bindings can
introduce a Pack</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P1061R10 <a href="https://wg21.link/P1061">[Latest]</a> <a href="https://wg21.link/P1061/status">[Status]</a></td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-11-22</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      CWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.com</a>&gt;<br>
      Jonathan Wakely<br>&lt;<a href="mailto:cxx@kayari.org" class="email">cxx@kayari.org</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">1</span> Revision
History<span></span></a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">2</span> Motivation<span></span></a></li>
<li><a href="#proposal" id="toc-proposal"><span class="toc-section-number">3</span> Proposal<span></span></a>
<ul>
<li><a href="#other-languages" id="toc-other-languages"><span class="toc-section-number">3.1</span> Other
Languages<span></span></a></li>
<li><a href="#implementation-burden" id="toc-implementation-burden"><span class="toc-section-number">3.2</span> Implementation
Burden<span></span></a></li>
<li><a href="#removing-packs-outside-of-templates" id="toc-removing-packs-outside-of-templates"><span class="toc-section-number">3.3</span> Removing Packs outside of
Templates<span></span></a></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">3.4</span> Implementation
Experience<span></span></a></li>
</ul></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">4</span> Wording<span></span></a>
<ul>
<li><a href="#feature-test-macro" id="toc-feature-test-macro"><span class="toc-section-number">4.1</span> Feature-Test
Macro<span></span></a></li>
</ul></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">5</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">6</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="revision-history"><span class="header-section-number">1</span>
Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>R10 removes the ability to use packs outside of templates.</p>
<p>R9 has minor wording changes and updates the <a href="#implementation-experience">implementation experience</a>
section.</p>
<p>R8 re-adds the <a href="#namespace-scope-packs">namespace-scope
exclusion</a>, and more wording updates. Also rebases the wording to
account for <span class="citation" data-cites="P0609R3">[<a href="https://wg21.link/p0609r3" role="doc-biblioref">P0609R3</a>]</span>.</p>
<p>R7 attempts to word the post-Varna version.</p>
<p>R6 has added wording changes and adds some more complicated examples
to motivate how to actually word this paper.</p>
<p>R5 has minor wording changes.</p>
<p>R4 significantly improves the wording after review in Issaquah.</p>
<p>R3 removes the exclusion of namespace-scope per <a href="https://github.com/cplusplus/papers/issues/294#issuecomment-1234578812">EWG
guidance</a>.</p>
<p>R2 adds a section about implementation complexity, implementation
experience, and wording.</p>
<p>R1 of this paper <span class="citation" data-cites="P1061R1">[<a href="https://wg21.link/p1061r1" role="doc-biblioref">P1061R1</a>]</span> was presented to EWG in Belfast
2019 <span class="citation" data-cites="P1061R1.Minutes">[<a href="https://wiki.edg.com/bin/view/Wg21belfast/P1061-EWG" role="doc-biblioref">P1061R1.Minutes</a>]</span> which approved the
direction as presented (12-5-2-0-1).</p>
<p>R0 of this paper <span class="citation" data-cites="P1061R0">[<a href="https://wg21.link/p1061r0" role="doc-biblioref">P1061R0</a>]</span> was presented to EWGI in Kona
2019 <span class="citation" data-cites="P1061R0.Minutes">[<a href="http://wiki.edg.com/bin/view/Wg21kona2019/P1061" role="doc-biblioref">P1061R0.Minutes</a>]</span>, who reviewed it
favorably and thought this was a good investment of our time
(4-3-4-1-0). The consensus in the room was that the restriction that the
introduced pack need not be the trailing identifier.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="motivation"><span class="header-section-number">2</span>
Motivation<a href="#motivation" class="self-link"></a></h1>
<p>Function parameter packs and tuples are conceptually very similar.
Both are heterogeneous sequences of objects. Some problems are easier to
solve with a parameter pack, some are easier to solve with a
<code class="sourceCode cpp">tuple</code>. Today, it’s trivial to
convert a pack to a <code class="sourceCode cpp">tuple</code>, but it’s
somewhat more involved to convert a
<code class="sourceCode cpp">tuple</code> to a pack. You have to go
through <code class="sourceCode cpp">std<span class="op">::</span>apply<span class="op">()</span></code>
<span class="citation" data-cites="N3915">[<a href="https://wg21.link/n3915" role="doc-biblioref">N3915</a>]</span>:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>tuple<span class="op">&lt;</span>A, B, C<span class="op">&gt;</span> tup <span class="op">=</span> <span class="op">...</span>;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>apply<span class="op">([&amp;](</span><span class="kw">auto</span><span class="op">&amp;&amp;...</span> elems<span class="op">){</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// now I have a pack</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>, tup<span class="op">)</span>;</span></code></pre></div>
</blockquote>
</div>
<p>This is great for cases where we just need to call a [non-overloaded]
function or function object, but rapidly becomes much more awkward as we
dial up the complexity. Not to mention if I want to return from the
outer scope based on what these elements have to be.</p>
<p>How do we compute the dot product of two
<code class="sourceCode cpp">tuple</code>s? It’s a choose your own
adventure of awkward choices:</p>
<table style="width:100%">
<tr>
<th style="width:50%">
Nested
<code class="sourceCode cpp">apply<span class="op">()</span></code>
</th>
<th style="width:50%">
Using <code class="sourceCode cpp">index_sequence</code>
</th>
</tr>
<tr>
<td>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> P, <span class="kw">class</span> Q<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot_product<span class="op">(</span>P p, Q q<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>apply<span class="op">([&amp;](</span><span class="kw">auto</span><span class="op">...</span> p_elems<span class="op">){</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>apply<span class="op">([&amp;](</span><span class="kw">auto</span><span class="op">...</span> q_elems<span class="op">){</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="op">(...</span> <span class="op">+</span> <span class="op">(</span>p_elems <span class="op">*</span> q_elems<span class="op">))</span>;</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>, q<span class="op">)</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>, p<span class="op">)</span>;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
<td>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">size_t</span><span class="op">...</span> Is, <span class="kw">class</span> P, <span class="kw">class</span> Q<span class="op">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot_product<span class="op">(</span>std<span class="op">::</span>index_sequence<span class="op">&lt;</span>Is<span class="op">...&gt;</span>, P p, Q, q<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(...</span> <span class="op">+</span> <span class="op">(</span>std<span class="op">::</span>get<span class="op">&lt;</span>Is<span class="op">&gt;(</span>p<span class="op">)</span> <span class="op">*</span> std<span class="op">::</span>get<span class="op">&lt;</span>Is<span class="op">&gt;(</span>q<span class="op">)))</span>;</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> P, <span class="kw">class</span> Q<span class="op">&gt;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot_product<span class="op">(</span>P p, Q q<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> dot_product<span class="op">(</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>make_index_sequence<span class="op">&lt;</span>std<span class="op">::</span>tuple_size<span class="op">&lt;</span>P<span class="op">&gt;::</span>value<span class="op">&gt;{}</span>,</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>        p, q<span class="op">)</span>;</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
</tr>
</table>
<p>Regardless of which option you dislike the least, both are limited to
only
<code class="sourceCode cpp">std<span class="op">::</span>tuple</code>s.
We don’t have the ability to do this at all for any of the other kinds
of types that can be used in a structured binding declaration <span class="citation" data-cites="P0144R2">[<a href="https://wg21.link/p0144r2" role="doc-biblioref">P0144R2</a>]</span> - because we need to explicit
list the correct number of identifiers, and we might not know how many
there are.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="proposal"><span class="header-section-number">3</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>We propose to extend the structured bindings syntax to allow the user
to introduce a pack as (at most) one of the identifiers:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>tuple<span class="op">&lt;</span>X, Y, Z<span class="op">&gt;</span> f<span class="op">()</span>;</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="op">[</span>x,y,z<span class="op">]</span> <span class="op">=</span> f<span class="op">()</span>;          <span class="co">// OK today</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="op">[...</span>xs<span class="op">]</span> <span class="op">=</span> f<span class="op">()</span>;          <span class="co">// proposed: xs is a pack of length three containing an X, Y, and a Z</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="op">[</span>x, <span class="op">...</span>rest<span class="op">]</span> <span class="op">=</span> f<span class="op">()</span>;     <span class="co">// proposed: x is an X, rest is a pack of length two (Y and Z)</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="op">[</span>x,y,z, <span class="op">...</span>rest<span class="op">]</span> <span class="op">=</span> f<span class="op">()</span>; <span class="co">// proposed: rest is an empty pack</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="op">[</span>x, <span class="op">...</span>rest, z<span class="op">]</span> <span class="op">=</span> f<span class="op">()</span>;  <span class="co">// proposed: x is an X, rest is a pack of length one</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>                             <span class="co">//   consisting of the Y, z is a Z</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="op">[...</span>a, <span class="op">...</span>b<span class="op">]</span> <span class="op">=</span> f<span class="op">()</span>;     <span class="co">// ill-formed: multiple packs</span></span></code></pre></div>
</blockquote>
</div>
<p>If we additionally add the structured binding customization machinery
to <code class="sourceCode cpp">std<span class="op">::</span>integer_sequence</code>,
this could greatly simplify generic code:</p>
<table style="width:100%">
<tr>
<th>
Today
</th>
<th>
Proposed
</th>
</tr>
<tr>
<td colspan="2">
<center>
Implementing <code class="sourceCode cpp">std<span class="op">::</span>apply<span class="op">()</span></code>
</center>
</td>
</tr>
<tr>
<td>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> detail <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> F, <span class="kw">class</span> Tuple, std<span class="op">::</span><span class="dt">size_t</span><span class="op">...</span> I<span class="op">&gt;</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> apply_impl<span class="op">(</span>F <span class="op">&amp;&amp;</span>f, Tuple <span class="op">&amp;&amp;</span>t,</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>index_sequence<span class="op">&lt;</span>I<span class="op">...&gt;)</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>invoke<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>F<span class="op">&gt;(</span>f<span class="op">)</span>,</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>get<span class="op">&lt;</span>I<span class="op">&gt;(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Tuple<span class="op">&gt;(</span>t<span class="op">))...)</span>;</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> F, <span class="kw">class</span> Tuple<span class="op">&gt;</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> apply<span class="op">(</span>F <span class="op">&amp;&amp;</span>f, Tuple <span class="op">&amp;&amp;</span>t<span class="op">)</span></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> detail<span class="op">::</span>apply_impl<span class="op">(</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>forward<span class="op">&lt;</span>F<span class="op">&gt;(</span>f<span class="op">)</span>, std<span class="op">::</span>forward<span class="op">&lt;</span>Tuple<span class="op">&gt;(</span>t<span class="op">)</span>,</span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>make_index_sequence<span class="op">&lt;</span>std<span class="op">::</span>tuple_size_v<span class="op">&lt;</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>            std<span class="op">::</span>decay_t<span class="op">&lt;</span>Tuple<span class="op">&gt;&gt;&gt;{})</span>;</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
<td>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> F, <span class="kw">class</span> Tuple<span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> apply<span class="op">(</span>F <span class="op">&amp;&amp;</span>f, Tuple <span class="op">&amp;&amp;</span>t<span class="op">)</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span><span class="op">&amp;&amp;</span> <span class="op">[...</span>elems<span class="op">]</span> <span class="op">=</span> t;</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>invoke<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>F<span class="op">&gt;(</span>f<span class="op">)</span>,</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>        forward_like<span class="op">&lt;</span>Tuple, <span class="kw">decltype</span><span class="op">(</span>elems<span class="op">)&gt;(</span>elems<span class="op">)...)</span>;</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
</tr>
<tr>
<td colspan="2">
<center>
<code class="sourceCode cpp">dot_product<span class="op">()</span></code>,
nested
</center>
</td>
</tr>
<tr>
<td>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> P, <span class="kw">class</span> Q<span class="op">&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot_product<span class="op">(</span>P p, Q q<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>apply<span class="op">([&amp;](</span><span class="kw">auto</span><span class="op">...</span> p_elems<span class="op">){</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>apply<span class="op">([&amp;](</span><span class="kw">auto</span><span class="op">...</span> q_elems<span class="op">){</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="op">(...</span> <span class="op">+</span> <span class="op">(</span>p_elems <span class="op">*</span> q_elems<span class="op">))</span>;</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>, q<span class="op">)</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>, p<span class="op">)</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
<td>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> P, <span class="kw">class</span> Q<span class="op">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot_product<span class="op">(</span>P p, Q q<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// no indirection!</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span><span class="op">&amp;&amp;</span> <span class="op">[...</span>p_elems<span class="op">]</span> <span class="op">=</span> p;</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span><span class="op">&amp;&amp;</span> <span class="op">[...</span>q_elems<span class="op">]</span> <span class="op">=</span> q;</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(...</span> <span class="op">+</span> <span class="op">(</span>p_elems <span class="op">*</span> q_elems<span class="op">))</span>;</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
</tr>
<tr>
<td colspan="2">
<center>
<code class="sourceCode cpp">dot_product<span class="op">()</span></code>,
with <code class="sourceCode cpp">index_sequence</code>
</center>
</td>
</tr>
<tr>
<td>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="dt">size_t</span><span class="op">...</span> Is, <span class="kw">class</span> P, <span class="kw">class</span> Q<span class="op">&gt;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot_product<span class="op">(</span>std<span class="op">::</span>index_sequence<span class="op">&lt;</span>Is<span class="op">...&gt;</span>, P p, Q, q<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(...</span> <span class="op">+</span> <span class="op">(</span>std<span class="op">::</span>get<span class="op">&lt;</span>Is<span class="op">&gt;(</span>p<span class="op">)</span> <span class="op">*</span> std<span class="op">::</span>get<span class="op">&lt;</span>Is<span class="op">&gt;(</span>q<span class="op">)))</span>;</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> P, <span class="kw">class</span> Q<span class="op">&gt;</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot_product<span class="op">(</span>P p, Q q<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> dot_product<span class="op">(</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>make_index_sequence<span class="op">&lt;</span>std<span class="op">::</span>tuple_size_v<span class="op">&lt;</span>P<span class="op">&gt;&gt;{}</span>,</span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>        p, q<span class="op">)</span>;</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
<td>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> P, <span class="kw">class</span> Q<span class="op">&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> dot_product<span class="op">(</span>P p, Q q<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// no helper function necessary!</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[...</span>Is<span class="op">]</span> <span class="op">=</span> std<span class="op">::</span>make_index_sequence<span class="op">&lt;</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>tuple_size_v<span class="op">&lt;</span>P<span class="op">&gt;&gt;{}</span>;</span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(...</span> <span class="op">+</span> <span class="op">(</span>std<span class="op">::</span>get<span class="op">&lt;</span>Is<span class="op">&gt;(</span>p<span class="op">)</span> <span class="op">*</span> std<span class="op">::</span>get<span class="op">&lt;</span>Is<span class="op">&gt;(</span>q<span class="op">)))</span>;</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</td>
</tr>
</table>
<p>Not only are these implementations more concise, but they are also
more functional. I can just as easily use
<code class="sourceCode cpp">apply<span class="op">()</span></code> with
user-defined types as I can with
<code class="sourceCode cpp">std<span class="op">::</span>tuple</code>:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Point <span class="op">{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> x, y, z;</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>Point getPoint<span class="op">()</span>;</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> calc<span class="op">(</span><span class="dt">int</span>, <span class="dt">int</span>, <span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="dt">double</span> result <span class="op">=</span> std<span class="op">::</span>apply<span class="op">(</span>calc, getPoint<span class="op">())</span>; <span class="co">// ill-formed today, ok with proposed implementation</span></span></code></pre></div>
</blockquote>
</div>
<h2 data-number="3.1" id="other-languages"><span class="header-section-number">3.1</span> Other Languages<a href="#other-languages" class="self-link"></a></h2>
<p>Python 2 had always allowed for a syntax similar to C++17 structured
bindings, where you have to provide all the identifiers:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> a, b, c, d, e <span class="op">=</span> <span class="bu">range</span>(<span class="dv">5</span>) <span class="co"># ok</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> a, <span class="op">*</span>b <span class="op">=</span> <span class="bu">range</span>(<span class="dv">3</span>)</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  File <span class="st">&quot;&lt;stdin&gt;&quot;</span>, line <span class="dv">1</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    a, <span class="op">*</span>b <span class="op">=</span> <span class="bu">range</span>(<span class="dv">3</span>)</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>       <span class="op">^</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="pp">SyntaxError</span>: invalid syntax</span></code></pre></div>
</blockquote>
</div>
<p>But you could not do any more than that. Python 3 went one step
further by way of PEP-3132 <span class="citation" data-cites="PEP.3132">[<a href="https://www.python.org/dev/peps/pep-3132/" role="doc-biblioref">PEP.3132</a>]</span>. That proposal allowed for a
single starred identifier to be used, which would bind to all the
elements as necessary:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> a, <span class="op">*</span>b, c <span class="op">=</span> <span class="bu">range</span>(<span class="dv">5</span>)</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> a</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="dv">0</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> c</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="dv">4</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;&gt;&gt;</span> b</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>]</span></code></pre></div>
</blockquote>
</div>
<p>The Python 3 behavior is synonymous with what is being proposed here.
Notably, from that PEP:</p>
<blockquote>
<p>Possible changes discussed were:</p>
<ul>
<li>Only allow a starred expression as the last item in the exprlist.
This would simplify the unpacking code a bit and allow for the starred
expression to be assigned an iterator. This behavior was rejected
because it would be too surprising.</li>
</ul>
</blockquote>
<p>R0 of this proposal only allowed a pack to be introduced as the last
item, which was changed in R1.</p>
<h2 data-number="3.2" id="implementation-burden"><span class="header-section-number">3.2</span> Implementation Burden<a href="#implementation-burden" class="self-link"></a></h2>
<p>Unfortunately, this proposal has some implementation complexity. The
issue is not so much this aspect:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span>typeanme Tuple<span class="op">&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> sum_template<span class="op">(</span>Tuple tuple<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[...</span>elems<span class="op">]</span> <span class="op">=</span> tuple;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(...</span> <span class="op">+</span> elems<span class="op">)</span>;</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>This part is more or less straightforward - we have a dependent type
and we introduce a pack from it, but we’re already in a template context
where dealing with packs is just a normal thing.</p>
<p>The problem is this aspect:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> sum_non_template<span class="op">(</span>SomeConreteType tuple<span class="op">)</span> <span class="op">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[...</span>elems<span class="op">]</span> <span class="op">=</span> tuple;</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(...</span> <span class="op">+</span> elems<span class="op">)</span>;</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>We have not yet in the history of C++ had this notion of packs
outside of dependent contexts. This is completely novel, and imposes a
burden on implementations to have to track packs outside of templates
where they previously had not.</p>
<p>However, in our estimation, this functionality is going to come to
C++ in one form or other fairly soon. Reflection, in the latest form of
<span class="citation" data-cites="P1240R2">[<a href="https://wg21.link/p1240r2" role="doc-biblioref">P1240R2</a>]</span>, has many examples of
introducing packs in non-template contexts as well - through the notion
of a <em>reflection range</em>. That paper introduces several reifiers
that can manipilate a newly-introduced pack, such as:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>meta<span class="op">::</span>info t_args<span class="op">[]</span> <span class="op">=</span> <span class="op">{</span> <span class="op">^</span><span class="dt">int</span>, <span class="op">^</span><span class="dv">42</span> <span class="op">}</span>;</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T, T<span class="op">&gt;</span> <span class="kw">struct</span> X <span class="op">{}</span>;</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>X<span class="op">&lt;...[:</span>t_args<span class="op">:]...&gt;</span> x; <span class="co">// Same as &quot;X&lt;int, 42&gt; x;&quot;.</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span>, <span class="kw">typename</span><span class="op">&gt;</span> <span class="kw">struct</span> Y <span class="op">{}</span>;</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>Y<span class="op">&lt;...[:</span>t_args<span class="op">:]...&gt;</span> y; <span class="co">// Error: same as &quot;Y&lt;int, 42&gt; y;&quot;.</span></span></code></pre></div>
</blockquote>
</div>
<p>As with the structured bindings example in this paper - we have a
non-dependent object outside of a template that we’re using to introduce
a pack.</p>
<p>Furthermore, unlike some of the reflection examples, and some of the
more generic pack facilities proposed in <span class="citation" data-cites="P1858R2">[<a href="https://wg21.link/p1858r2" role="doc-biblioref">P1858R2</a>]</span>, this paper offers a nice
benefit: all packs must still be declared before use. Even in the
<code class="sourceCode cpp">sum_non_template</code> example which, as
the name suggests, is not a template in any way, the pack
<code class="sourceCode cpp">elems</code> needs an initial declaration.
So any machinery that implementations need to track packs doesn’t need
to be enabled everywhere - only when a pack declaration has been
seen.</p>
<h2 data-number="3.3" id="removing-packs-outside-of-templates"><span class="header-section-number">3.3</span> Removing Packs outside of
Templates<a href="#removing-packs-outside-of-templates" class="self-link"></a></h2>
<p>The <span class="citation" data-cites="P1061R9">[<a href="https://wg21.link/p1061r9" role="doc-biblioref">P1061R9</a>]</span> design relied upon introducing
an <em>implicit template region</em> when a structured binding pack was
declared, which implicitly turns the rest of your function into a
function template. That complexity, coupled with persistent opposition
due to implementation complexity, led to Evolution rejecting <span class="citation" data-cites="P1061R9">[<a href="https://wg21.link/p1061r9" role="doc-biblioref">P1061R9</a>]</span> at the Wrocław meeting.</p>
<p>Since R10, this paper removes support for packs outside of templates,
which removes the implementor objection and the design complexity. All
of the complex examples from the original approach have been removed
from this paper for brevity.</p>
<h2 data-number="3.4" id="implementation-experience"><span class="header-section-number">3.4</span> Implementation Experience<a href="#implementation-experience" class="self-link"></a></h2>
<p>Jason Rice has implemented the <span class="citation" data-cites="P1061R9">[<a href="https://wg21.link/p1061r9" role="doc-biblioref">P1061R9</a>]</span> design in a <a href="https://github.com/ricejasonf/llvm-project/commits/ricejasonf/p1061">clang</a>.
As far as we’ve been able to ascertain, it works great. It was initially
done early in the process, before the concept of “implicit template
region” was introduced in the wording — when he was updating the
implementation to account for the new rules and to make sure that all
the examples in the paper compiled, he noted that “Honestly, the
implicit template region vastly simplified things, and much code was
deleted.”</p>
<p>It is also <a href="https://godbolt.org/z/Tnz4e1dY9">available on
Compiler Explorer</a>, including <a href="https://godbolt.org/z/6ebbqb1Kh">the most complex example</a> in
the the original paper.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="wording"><span class="header-section-number">4</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>Add a drive-by fix to <span>7.5.7 <a href="https://wg21.link/expr.prim.fold">[expr.prim.fold]</a></span>
after paragraph 3:</p>
<div class="std ins">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">π</a></span>
<span class="addu">A fold expression is a pack expansion.</span></p>
</blockquote>
</div>
<p>Add a new grammar option for <em>simple-declaration</em> to <span>9.1
<a href="https://wg21.link/dcl.pre">[dcl.pre]</a></span> (note that this
accounts for <span class="citation" data-cites="P0609R3">[<a href="https://wg21.link/p0609r3" role="doc-biblioref">P0609R3</a>]</span> by renaming the grammar
productions prefixed with
<code class="sourceCode cpp"><em>attributed</em></code> to
<code class="sourceCode cpp"><em>sb</em></code>):</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb15"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="st">- <em>attributed-identifier</em>:</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="st">-     <em>identifier</em> <em>attribute-specifier-seq</em><sub>opt</sub></span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="va">+ <em>sb-identifier</em>:</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="va">+     <span class="diffins"><code class="sourceCode cpp"><span class="op">...</span></code><sub>opt</sub></span> <em>identifier</em> <em>attribute-specifier-seq</em><sub>opt</sub></span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="st">- <em>attributed-identifier-list</em>:</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a><span class="st">-     <em>attributed-identifier</em></span></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="st">-     <em>attributed-identifier-list</em>, <em>attributed-identifier</em></span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a><span class="va">+ <em>sb-identifier-list</em>:</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a><span class="va">+     <em>sb-identifier</em></span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a><span class="va">+     <em>sb-identifier-list</em>, <em>sb-identifier</em></span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a>  <em>structured-binding-declaration</em>:</span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="st">-    <em>attribute-specifier-seq</em><sub>opt</sub> <em>decl-specifier-seq</em> <em>ref-qualifier</em><sub>opt</sub> [ <span class="diffdel"><em>attributed-identifier-list</em></span> ]</span></span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a><span class="va">+    <em>attribute-specifier-seq</em><sub>opt</sub> <em>decl-specifier-seq</em> <em>ref-qualifier</em><sub>opt</sub> [ <span class="diffins"><em>sb-identifier-list</em></span> ]</span></span></code></pre></div>
</div>
</blockquote>
</div>
<p>Change <span>9.1 <a href="https://wg21.link/dcl.pre">[dcl.pre]</a></span>/6:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">6</a></span>
A <em>simple-declaration</em> with a
<code class="sourceCode cpp"><em>structured-binding-declaration</em></code>
is called a structured binding declaration ([dcl.struct.bind]). Each
<em>decl-specifier</em> in the <em>decl-specifier-seq</em> shall be
<code class="sourceCode cpp"><span class="kw">static</span></code>,
<code class="sourceCode cpp"><span class="kw">thread_local</span></code>,
<code class="sourceCode cpp"><span class="kw">auto</span></code>
([dcl.spec.auto]), or a <em>cv</em>-qualifier. <span class="addu">The
declaration shall contain at most one <em>sb-identifier</em> whose
<em>identifier</em> is preceded by an ellipsis. If the declaration
contains any such <em>sb-identifier</em>, it shall declare a templated
entity ([temp.pre]).</span></p>
</blockquote>
</div>
<p>Change <span>9.6 <a href="https://wg21.link/dcl.struct.bind">[dcl.struct.bind]</a></span>
paragraph 1:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">1</a></span>
A structured binding declaration introduces the <i>identifier</i>s
v<sub>0</sub>, v<sub>1</sub>, v<sub>2</sub>, …<span class="addu">,
v<sub>N-1</sub></span> of the <span class="rm" style="color: #bf0303"><del><i>attribute-identifier-list-list</i></del></span>
<span class="addu"><code class="sourceCode cpp"><em>sb-identifier-list</em></code></span>
as names ([basic.scope.declarative]) <span class="rm" style="color: #bf0303"><del>of <em>structured
bindings</em></del></span>. <span class="addu">An
<code class="sourceCode cpp"><em>sb-identifier</em></code> that contains
an ellipsis introduces a structured binding pack ([temp.variadic]). A
<em>structured binding</em> is either an
<code class="sourceCode cpp"><em>sb-identifier</em></code> that does not
contain an ellipsis or an element of a structured binding pack.</span>
The optional
<code class="sourceCode cpp"><em>attribute-specifier-seq</em></code> of
an <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default"><em>attributed-identifier</em></code></span></del></span>
<span class="addu"><code class="sourceCode cpp"><em>sb-identifier</em></code></span>
appertains to the <span class="addu">associated</span> structured
binding<span class="addu">s</span> <span class="rm" style="color: #bf0303"><del>so introduced</del></span>. Let <i>cv</i>
denote the <i>cv-qualifiers</i> in the
<code class="sourceCode cpp"><em>decl-specifier-seq</em></code>.</p>
</blockquote>
</div>
<p>Introduce new paragraphs after <span>9.6 <a href="https://wg21.link/dcl.struct.bind">[dcl.struct.bind]</a></span>
paragraph 1, introducing the terms “structured binding size” and
SB<sub><em>i</em></sub>:</p>
<div class="std ins">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">1+1</a></span>
The <em>structured binding size</em> of
<code class="sourceCode cpp">E</code>, as defined below, is the number
of structured bindings that need to be introduced by the structured
binding declaration. If there is no structured binding pack, then the
number of elements in the <em>sb-identifier-list</em> shall be equal to
the structured binding size of <code class="sourceCode cpp">E</code>.
Otherwise, the number of non-pack elements shall be no more than the
structured binding size of <code class="sourceCode cpp">E</code>; the
number of elements of the structured binding pack is the structured
binding size of <code class="sourceCode cpp">E</code> less the number of
non-pack elements in the
<code class="sourceCode cpp"><em>sb-identifier-list</em></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">1+2</a></span>
Let SB<sub><em>i</em></sub> denote the <em>i</em><sup>th</sup>
structured binding in the structured binding declaration after expanding
the structured binding pack, if any. [ <em>Note</em>: If there is no
structured binding pack, then SB<sub><em>i</em></sub> denotes
v<sub><em>i</em></sub>. - <em>end note</em> ]</p>
<div class="example">
<span>[ <em>Example 1:</em> </span>
<div class="sourceCode" id="cb16"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>struct C { int x, y, z; };</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>template &lt;class T&gt;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>void now_i_know_my() {</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  auto [a, b, c] = C(); // OK, SB<sub>0</sub> is a, SB<sub>1</sub> is b, and SB<sub>2</sub> is c</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>  auto [d, ...e] = C(); // OK, SB<sub>0</sub> is d, the pack e (v<sub>1</sub>) contains two structured bindings: SB<sub>1</sub> and SB<sub>2</sub></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>  auto [...f, g] = C(); // OK, the pack f (v<sub>0</sub>) contains two structured bindings: SB<sub>0</sub> and SB<sub>1</sub>, and SB<sub>2</sub> is g</span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  auto [h, i, j, ...k] = C(); // OK, the pack k is empty</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>  auto [l, m, n, o, ...p] = C(); // error: structured binding size is too small</span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
</blockquote>
</div>
<p>Change <span>9.6 <a href="https://wg21.link/dcl.struct.bind">[dcl.struct.bind]</a></span>
paragraph 3 to define a structured binding size and extend the
example:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">3</a></span>
If <code class="sourceCode cpp">E</code> is an array type with element
type <code>T</code>, <span class="rm" style="color: #bf0303"><del>the
number of elements in the <i>attributed-identifier-list</i> shall
be</del></span> <span class="addu">the structured binding size of
<code class="sourceCode cpp">E</code> is</span> equal to the number of
elements of <code class="sourceCode cpp">E</code>. Each <span class="rm" style="color: #bf0303"><del><i>v<sub>i</sub></i></del></span> <span class="addu">SB<sub><em>i</em></sub></span> is the name of an lvalue
that refers to the element <i>i</i> of the array and whose type is
<code>T</code>; the referenced type is <code>T</code>. [<em>Note</em>:
The top-level <em>cv</em>-qualifiers of
<code class="sourceCode cpp">T</code> are <em>cv</em>. — <em>end
note</em>]</p>
<div class="example">
<span>[ <em>Example 2:</em> </span>
<div>
<div class="sourceCode" id="cb17"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>  auto f() -&gt; int(&amp;)[2];</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  auto [ x, y ] = f();            // x and y refer to elements in a copy of the array return value</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  auto&amp; [ xr, yr ] = f();         // xr and yr refer to elements in the array referred to by f&#39;s return value</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="va">+ auto g() -&gt; int(&amp;)[4];</span></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="va">+ template &lt;size_t N&gt;</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a><span class="va">+ void h(int (&amp;arr)[N]) {</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a><span class="va">+   auto [a, ...b, c] = arr;   // a names the first element of the array, b is a pack referring to the second and</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a><span class="va">+                              // third elements, and c names the fourth element</span></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a><span class="va">+   auto&amp; [...e] = arr;        // e is a pack referring to the four elements of the array</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a><span class="va">+ }</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a><span class="va">+ void call_h() {</span></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a><span class="va">+   h(g());</span></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a><span class="va">+ }</span></span></code></pre></div>
</div>
<span> — <em>end example</em> ]</span>
</div>
</blockquote>
</div>
<p>Change <span>9.6 <a href="https://wg21.link/dcl.struct.bind">[dcl.struct.bind]</a></span>
paragraph 4 to define a structured binding size:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">4</a></span>
Otherwise, if the <i>qualified-id</i>
<code>std::tuple_size&lt;E&gt;</code> names a complete type, the
expression
<code class="language-cpp">std::tuple_size&lt;E&gt;::value</code> shall
be a well-formed integral constant expression and the <span class="rm" style="color: #bf0303"><del>number of elements in the
<i>attributed-identifier-list</i> shall be</del></span> <span class="addu">structured binding size of
<code class="sourceCode cpp">E</code> is</span> equal to the value of
that expression. […] Each <span class="rm" style="color: #bf0303"><del><i>v<sub>i</sub></i></del></span> <span class="addu">SB<sub><em>i</em></sub></span> is the name of an lvalue of
type <code class>T<sub>i</sub></code> that refers to the object bound
to <code class>r<sub>i</sub></code>; the referenced type is
<code class>T<sub>i</sub></code>.</p>
</blockquote>
</div>
<p>Change <span>9.6 <a href="https://wg21.link/dcl.struct.bind">[dcl.struct.bind]</a></span>
paragraph 5 to define a structured binding size:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">5</a></span>
Otherwise, all of <code class="sourceCode cpp">E</code>’s non-static
data members shall be direct members of
<code class="sourceCode cpp">E</code> or of the same base class of
<code class="sourceCode cpp">E</code>, well-formed when named as
<code>e.name</code> in the context of the structured binding,
<code class="sourceCode cpp">E</code> shall not have an anonymous union
member, and the <span class="rm" style="color: #bf0303"><del>number of
elements in the <i>attributed-identifier-list</i> shall be</del></span>
<span class="addu">structured binding size of
<code class="sourceCode cpp">E</code> is</span> equal to the number of
non-static data members of <code class="sourceCode cpp">E</code>.
Designating the non-static data members of
<code class="sourceCode cpp">E</code> as <code class>m<sub>0</sub>,
m<sub>1</sub>, m<sub>2</sub>, . . .</code> (in declaration order), each
<span class="rm" style="color: #bf0303"><del><code class>v<sub>i</i></code></del></span>
<span class="addu">SB<sub><em>i</em></sub></span> is the name of an
lvalue that refers to the member <code class>m<sub>i</sub></code> of
<code class="sourceCode cpp">E</code> and whose type is <i>cv</i>
<code class>T<sub>i</sub></code>, where
<code class>T<sub>i</sub></code> is the declared type of that member;
the referenced type is <i>cv</i> <code class>T<sub>i</sub></code>.
The lvalue is a bit-field if that member is a bit-field.</p>
</blockquote>
</div>
<p>Add a new clause to <span>13.7.4 <a href="https://wg21.link/temp.variadic">[temp.variadic]</a></span>, after
paragraph 3:</p>
<div class="std ins">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_9" id="pnum_9">3+</a></span>
A <em>structured binding pack</em> is an <em>sb-identifier</em> that
introduces zero or more structured bindings ([dcl.struct.bind]).</p>
<div class="example">
<span>[ <em>Example 3:</em> </span>
<div class="sourceCode" id="cb18"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>auto foo() -&gt; int(&amp;)[2];</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>template &lt;class T&gt;</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>void g() {</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>  auto [...a] = foo();          // a is a structured binding pack containing 2 elements</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>  auto [b, c, ...d] = foo();    // d is a structured binding pack containing 0 elements</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
</blockquote>
</div>
<p>In <span>13.7.4 <a href="https://wg21.link/temp.variadic">[temp.variadic]</a></span>,
change paragraph 4:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">4</a></span>
A <em>pack</em> is a template parameter pack, a function parameter pack,
<span class="rm" style="color: #bf0303"><del>or</del></span> an
<em>init-capture</em> pack<span class="addu">, or a structured binding
pack</span>. The number of elements of a template parameter pack or a
function parameter pack is the number of arguments provided for the
parameter pack. The number of elements of an <em>init-capture</em> pack
is the number of elements in the pack expansion of its
<em>initializer</em>.</p>
</blockquote>
</div>
<p>In <span>13.7.4 <a href="https://wg21.link/temp.variadic">[temp.variadic]</a></span>,
paragraph 5 (describing pack expansions) remains unchanged.</p>
<p>In <span>13.7.4 <a href="https://wg21.link/temp.variadic">[temp.variadic]</a></span>, add a
bullet to paragraph 8:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">8</a></span>
Such an element, in the context of the instantiation, is interpreted as
follows:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">(8.1)</a></span>
if the pack is a template parameter pack, the element is a template
parameter ([temp.param]) of the corresponding kind (type or non-type)
designating the <i>i</i><sup>th</sup> corresponding type or value
template argument;</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">(8.2)</a></span>
if the pack is a function parameter pack, the element is an
<i>id-expression</i> designating the <i>i</i><sup>th</sup> function
parameter that resulted from instantiation of the function parameter
pack declaration; <span class="rm" style="color: #bf0303"><del>otherwise</del></span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">(8.3)</a></span>
if the pack is an <i>init-capture</i> pack, the element is an
<i>id-expression</i> designating the variable introduced by the
<i>i</i><sup>th</sup>th <i>init-capture</i> that resulted from
instantiation of the <i>init-capture</i> pack<span class="rm" style="color: #bf0303"><del>.</del></span> <span class="addu">;
otherwise</span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">(8.4)</a></span>
<span class="addu">if the pack is a structured binding pack, the element
is an <i>id-expression</i> designating the <i>i</i><sup>th</sup>
structured binding in the pack that resulted from the structured binding
declaration.</span></li>
</ul>
</blockquote>
</div>
<p>Add a bullet to <span>13.8.3.3 <a href="https://wg21.link/temp.dep.expr">[temp.dep.expr]</a></span>/3:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">3</a></span>
An <em>id-expression</em> is type-dependent if it is a
<em>template-id</em> that is not a concept-id and is dependent; or if
its terminal name is</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_17" id="pnum_17">(3.1)</a></span>
associated by name lookup with one or more declarations declared with a
dependent type,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_18" id="pnum_18">(3.2)</a></span>
associated by name lookup with a non-type template-parameter declared
with a type that contains a placeholder type,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_19" id="pnum_19">(3.3)</a></span>
associated by name lookup with a variable declared with a type that
contains a placeholder type ([dcl.spec.auto]) where the initializer is
type-dependent,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_20" id="pnum_20">(3.4)</a></span>
associated by name lookup with one or more declarations of member
functions of a class that is the current instantiation declared with a
return type that contains a placeholder type,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_21" id="pnum_21">(3.5)</a></span>
associated by name lookup with a structured binding declaration
([dcl.struct.bind]) whose brace-or-equal-initializer is
type-dependent,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_22" id="pnum_22">(3.5b)</a></span>
<span class="addu">associated by name lookup with a pack,</span></p>
<div class="addu">
<div class="example">
<span>[ <em>Example 4:</em> </span>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> C <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> g<span class="op">(...)</span>; <span class="co">// #1</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> f<span class="op">()</span> <span class="op">{</span></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>    C arr<span class="op">[</span><span class="dv">1</span><span class="op">]</span>;</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[...</span>e<span class="op">]</span> <span class="op">=</span> arr;</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>    g<span class="op">(</span>e<span class="op">...)</span>; <span class="co">// calls #2</span></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> g<span class="op">(</span>C<span class="op">)</span>; <span class="co">// #2</span></span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a>    f<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;()</span>;</span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
</div></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_23" id="pnum_23">(3.6)</a></span>
associated by name lookup with an entity captured by copy
([expr.prim.lambda.capture]) in a lambda-expression that has an explicit
object parameter whose type is dependent ([dcl.fct]),</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_24" id="pnum_24">(3.7)</a></span>
the identifier
<code class="sourceCode cpp"><span class="ot">__func__</span></code>
([dcl.fct.def.general]), where any enclosing function is a template, a
member of a class template, or a generic lambda,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_25" id="pnum_25">(3.8)</a></span>
a conversion-function-id that specifies a dependent type, or</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_26" id="pnum_26">(3.9)</a></span>
dependent</p></li>
</ul>
</blockquote>
</div>
<p>Add a carve-out for in <span>13.8.3.4 <a href="https://wg21.link/temp.dep.constexpr">[temp.dep.constexpr]</a></span>/4:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_27" id="pnum_27">4</a></span>
Expressions of the following form are value-dependent:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>sizeof ... ( identifier )</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>fold-expression</span></code></pre></div>
<p><span class="addu">unless the <em>identifier</em> is a structured
binding pack whose initializer is not dependent.</span></p>
</blockquote>
</div>
<h2 data-number="4.1" id="feature-test-macro"><span class="header-section-number">4.1</span> Feature-Test Macro<a href="#feature-test-macro" class="self-link"></a></h2>
<p>Bump <code class="sourceCode cpp">__cpp_structured_bindings</code> in
<span>15.11 <a href="https://wg21.link/cpp.predefined">[cpp.predefined]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb21"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="st">- __cpp_­structured_­bindings 201606L</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><span class="va">+ __cpp_­structured_­bindings 2024XXL</span></span></code></pre></div>
</div>
</blockquote>
</div>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="acknowledgements"><span class="header-section-number">5</span>
Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Thanks to Michael Park and Tomasz Kamiński for their helpful
feedback. Thanks to Richard Smith for help with the wording. Thanks
especially to Jason Rice for the implementation.</p>
<p>Thanks to John Spicer, Christof Meerwald, Jens Maurer, and everyone
else in Core for the wording help, mind-melting examples, and getting
this paper in shape.</p>
<h1 data-number="6" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">6</span>
References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-N3915" class="csl-entry" role="doc-biblioentry">
[N3915] Peter Sommerlad. 2014-02-14. apply() call a function with
arguments from a tuple (V3). <a href="https://wg21.link/n3915"><div class="csl-block">https://wg21.link/n3915</div></a>
</div>
<div id="ref-P0144R2" class="csl-entry" role="doc-biblioentry">
[P0144R2] Herb Sutter. 2016-03-16. Structured Bindings. <a href="https://wg21.link/p0144r2"><div class="csl-block">https://wg21.link/p0144r2</div></a>
</div>
<div id="ref-P0609R3" class="csl-entry" role="doc-biblioentry">
[P0609R3] Aaron Ballman. 2024-03-21. Attributes for Structured Bindings.
<a href="https://wg21.link/p0609r3"><div class="csl-block">https://wg21.link/p0609r3</div></a>
</div>
<div id="ref-P1061R0" class="csl-entry" role="doc-biblioentry">
[P1061R0] Barry Revzin, Jonathan Wakely. 2018-05-01. Structured Bindings
can introduce a Pack. <a href="https://wg21.link/p1061r0"><div class="csl-block">https://wg21.link/p1061r0</div></a>
</div>
<div id="ref-P1061R0.Minutes" class="csl-entry" role="doc-biblioentry">
[P1061R0.Minutes] EWGI. 2019. Kona 2019 EWGI: P1061R0. <a href="http://wiki.edg.com/bin/view/Wg21kona2019/P1061"><div class="csl-block">http://wiki.edg.com/bin/view/Wg21kona2019/P1061</div></a>
</div>
<div id="ref-P1061R1" class="csl-entry" role="doc-biblioentry">
[P1061R1] Barry Revzin, Jonathan Wakely. 2019-10-07. Structured Bindings
can introduce a Pack. <a href="https://wg21.link/p1061r1"><div class="csl-block">https://wg21.link/p1061r1</div></a>
</div>
<div id="ref-P1061R1.Minutes" class="csl-entry" role="doc-biblioentry">
[P1061R1.Minutes] EWG. 2019. Belfast 2020 EWG: P1061R1. <a href="https://wiki.edg.com/bin/view/Wg21belfast/P1061-EWG"><div class="csl-block">https://wiki.edg.com/bin/view/Wg21belfast/P1061-EWG</div></a>
</div>
<div id="ref-P1061R9" class="csl-entry" role="doc-biblioentry">
[P1061R9] Barry Revzin, Jonathan Wakely. 2024-08-24. Structured Bindings
can introduce a Pack. <a href="https://wg21.link/p1061r9"><div class="csl-block">https://wg21.link/p1061r9</div></a>
</div>
<div id="ref-P1240R2" class="csl-entry" role="doc-biblioentry">
[P1240R2] Daveed Vandevoorde, Wyatt Childers, Andrew Sutton, Faisal
Vali. 2022-01-14. Scalable Reflection. <a href="https://wg21.link/p1240r2"><div class="csl-block">https://wg21.link/p1240r2</div></a>
</div>
<div id="ref-P1858R2" class="csl-entry" role="doc-biblioentry">
[P1858R2] Barry Revzin. 2020-03-01. Generalized pack declaration and
usage. <a href="https://wg21.link/p1858r2"><div class="csl-block">https://wg21.link/p1858r2</div></a>
</div>
<div id="ref-PEP.3132" class="csl-entry" role="doc-biblioentry">
[PEP.3132] Georg Brandl. 2007. PEP 3132 – Extended Iterable Unpacking.
<a href="https://www.python.org/dev/peps/pep-3132/"><div class="csl-block">https://www.python.org/dev/peps/pep-3132/</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
