<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<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-04-14" />
  <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: #ffdddd;
--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: #FFC8EB;
border: none; }
code del { border: 1px solid #ECB3C7; }
</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>P1061R8</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-04-14</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="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">3.3</span> Implementation
Experience<span></span></a></li>
<li><a href="#handling-non-dependent-packs-in-the-wording" id="toc-handling-non-dependent-packs-in-the-wording"><span class="toc-section-number">3.4</span> Handling non-dependent packs in
the wording<span></span></a>
<ul>
<li><a href="#the-issaquah-example" id="toc-the-issaquah-example"><span class="toc-section-number">3.4.1</span> The Issaquah
Example<span></span></a></li>
<li><a href="#the-varna-example" id="toc-the-varna-example"><span class="toc-section-number">3.4.2</span> The Varna
Example<span></span></a></li>
<li><a href="#more-templates" id="toc-more-templates"><span class="toc-section-number">3.4.3</span> More
Templates<span></span></a></li>
</ul></li>
<li><a href="#namespace-scope-packs" id="toc-namespace-scope-packs"><span class="toc-section-number">3.5</span> Namespace-scope
packs<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>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="implementation-experience"><span class="header-section-number">3.3</span> Implementation Experience<a href="#implementation-experience" class="self-link"></a></h2>
<p>Jason Rice has implemented this 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.</p>
<p>It is also <a href="https://godbolt.org/z/Tnz4e1dY9">available on
Compiler Explorer</a>.</p>
<h2 data-number="3.4" id="handling-non-dependent-packs-in-the-wording"><span class="header-section-number">3.4</span> Handling non-dependent packs in
the wording<a href="#handling-non-dependent-packs-in-the-wording" class="self-link"></a></h2>
<p>The strategy the wording takes to handle is to introduce the concept
of an “implicit template region.” A structured binding pack declaration
introduces an implicit template region (if it’s not already a templated
entity), so that all entities declared within that scope are templated.
This is important for a bunch of examples that we’ll shortly see. That
implicit template region is instantiated at the end of the region.</p>
<p>Example from Richard Smith:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="kw">struct</span> X <span class="op">{</span> <span class="kw">using</span> type <span class="op">=</span> <span class="dt">int</span>; <span class="op">}</span>;</span>
<span id="cb15-2"><a href="#cb15-2" 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 class="dt">void</span> f<span class="op">()</span> <span class="op">{</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> Y <span class="op">{</span> <span class="dt">int</span> a, b; <span class="op">}</span>;</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="op">[...</span>v<span class="op">]</span> <span class="op">=</span> Y<span class="op">()</span>;</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>  X<span class="op">&lt;</span><span class="kw">sizeof</span><span class="op">...(</span>v<span class="op">)&gt;::</span>type x; <span class="co">// need typename or no?</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Is <code class="sourceCode cpp">X<span class="op">&lt;</span><span class="kw">sizeof</span><span class="op">...(</span>v<span class="op">)&gt;</span></code>
a dependent type or is the pack <code class="sourceCode cpp">v</code>
expanded eagerly because we already know its size? In this case we say a
<code class="sourceCode cpp"><span class="kw">sizeof</span><span class="op">...(</span>e<span class="op">)</span></code>
expression is <em>value-dependent</em> unless its referring to a
structured binding pack whose initializer is not dependent.
<code class="sourceCode cpp">Y<span class="op">()</span></code> isn’t
dependent, so <code class="sourceCode cpp"><span class="kw">sizeof</span><span class="op">...(</span>v<span class="op">)</span></code>
isn’t value dependent, so we don’t need
<code class="sourceCode cpp"><span class="kw">typename</span></code>
here.</p>
<p>That rule likewise handles this case:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Z <span class="op">{</span> <span class="dt">int</span> a, b; <span class="op">}</span>;</span>
<span id="cb16-2"><a href="#cb16-2" 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 class="dt">void</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> <span class="op">[...</span>v<span class="op">]</span> <span class="op">=</span> Z<span class="op">()</span>;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  X<span class="op">&lt;</span><span class="kw">sizeof</span><span class="op">...(</span>v<span class="op">)&gt;::</span>type x; <span class="co">// typename unnecessary</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<h3 data-number="3.4.1" id="the-issaquah-example"><span class="header-section-number">3.4.1</span> The Issaquah Example<a href="#the-issaquah-example" class="self-link"></a></h3>
<p>Here is an interesting example, courtesy of Christof Meerwald:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> C</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> i;</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">long</span> l;</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</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="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> D <span class="op">{</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="dt">int</span> J<span class="op">&gt;</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="dt">int</span> f<span class="op">(</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> D<span class="op">&lt;</span><span class="dt">long</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="dt">int</span> f;</span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="op">[</span> <span class="op">...</span> v <span class="op">]</span> <span class="op">=</span> C<span class="op">{</span> <span class="dv">1</span>, <span class="dv">0</span> <span class="op">}</span>;</span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> x <span class="op">=</span> <span class="op">(</span> <span class="op">...</span> <span class="op">+</span> <span class="op">(</span>D<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>v<span class="op">)&gt;::</span>f<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;(</span><span class="dv">2</span><span class="op">))</span> <span class="op">)</span>;</span></code></pre></div>
</blockquote>
</div>
<p>This example demonstrates the need for having
<code class="sourceCode cpp"><span class="kw">typename</span></code>
and/or
<code class="sourceCode cpp"><span class="kw">template</span></code> to
disambiguate, even if we’re not in a template context.
<code class="sourceCode cpp">v</code> still needs to behave like a
regular function parameter pack in this context - it still needs to be
depenent.</p>
<h3 data-number="3.4.2" id="the-varna-example"><span class="header-section-number">3.4.2</span> The Varna Example<a href="#the-varna-example" class="self-link"></a></h3>
<p>Here is an interesting example, also courtesy of Christof
Meerwald:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> C <span class="op">{</span> <span class="dt">int</span> j; <span class="dt">long</span> l; <span class="op">}</span>;</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><span class="dt">int</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span> <span class="op">...</span> i <span class="op">]</span> <span class="op">=</span> C<span class="op">{</span> <span class="dv">1</span>, <span class="dv">2</span><span class="bu">L</span> <span class="op">}</span>;</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(</span> <span class="op">[</span>c <span class="op">=</span> i<span class="op">]</span> <span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span>c<span class="op">)</span> <span class="op">&gt;</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">long</span><span class="op">))</span> <span class="op">{</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>            <span class="kw">static_assert</span><span class="op">(</span><span class="kw">false</span><span class="op">)</span>; <span class="co">// error?</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>        <span class="kw">struct</span> C <span class="op">{</span></span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>            <span class="co">// error, not templated?</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>            <span class="dt">int</span> f<span class="op">()</span> <span class="kw">requires</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span>c<span class="op">)</span> <span class="op">==</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">int</span><span class="op">))</span> <span class="op">{</span> <span class="cf">return</span> <span class="dv">1</span>; <span class="op">}</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>            <span class="co">// error, not templated?</span></span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>            <span class="dt">int</span> f<span class="op">()</span> <span class="kw">requires</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span>c<span class="op">)</span> <span class="op">!=</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">int</span><span class="op">))</span> <span class="op">{</span> <span class="cf">return</span> <span class="dv">2</span>; <span class="op">}</span></span>
<span id="cb18-16"><a href="#cb18-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>;</span>
<span id="cb18-17"><a href="#cb18-17" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> C<span class="op">{}.</span>f<span class="op">()</span>;</span>
<span id="cb18-18"><a href="#cb18-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="op">()</span> <span class="op">+</span> <span class="op">...</span>  <span class="op">+</span> <span class="dv">0</span> <span class="op">)</span>;</span>
<span id="cb18-19"><a href="#cb18-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb18-20"><a href="#cb18-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-21"><a href="#cb18-21" aria-hidden="true" tabindex="-1"></a><span class="co">// error?</span></span>
<span id="cb18-22"><a href="#cb18-22" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> v <span class="op">=</span> g<span class="op">()</span>;</span></code></pre></div>
</blockquote>
</div>
<p>What happens here? Core’s intent is that this example is valid - the
first <code class="sourceCode cpp"><span class="kw">static_assert</span></code>
declaration does not fire, this declares two different types
<code class="sourceCode cpp">C</code>, both of which are valid, and
<code class="sourceCode cpp">v</code> is initialized with the value
<code class="sourceCode cpp"><span class="dv">3</span></code>.</p>
<p>Here’s an addendum from Jason Merrill, Jens Maurer, and John Spicer,
slightly altered and somewhat gratuitously formatted hoping that it’s
possible to understand:</p>
<div class="std">
<blockquote>
<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="dt">int</span> j; <span class="dt">long</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">int</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span> <span class="op">...</span> i <span class="op">]</span> <span class="op">=</span> C<span class="op">{</span> <span class="dv">1</span>, <span class="dv">2</span><span class="bu">L</span> <span class="op">}</span>;</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">...(</span>i<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>        <span class="kw">static_assert</span><span class="op">(</span><span class="kw">false</span><span class="op">)</span>; <span class="co">// #1</span></span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(</span></span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a>      <span class="co">// E1</span></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>      <span class="op">[]{</span></span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a>          <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span><span class="dt">int</span><span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a>              <span class="kw">static_assert</span><span class="op">(</span><span class="kw">false</span><span class="op">)</span>; <span class="co">// #2</span></span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span></span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a>          <span class="cf">return</span> <span class="dv">1</span>;</span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a>      <span class="op">}()</span></span>
<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a>      <span class="op">*</span></span>
<span id="cb19-19"><a href="#cb19-19" aria-hidden="true" tabindex="-1"></a>      <span class="co">// E2</span></span>
<span id="cb19-20"><a href="#cb19-20" aria-hidden="true" tabindex="-1"></a>      <span class="op">[</span>c<span class="op">=</span>i<span class="op">]{</span></span>
<span id="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a>          <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span>c<span class="op">)</span> <span class="op">&gt;</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">long</span><span class="op">))</span> <span class="op">{</span></span>
<span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a>              <span class="kw">static_assert</span><span class="op">(</span><span class="kw">false</span><span class="op">)</span>; <span class="co">// #3</span></span>
<span id="cb19-23"><a href="#cb19-23" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span></span>
<span id="cb19-24"><a href="#cb19-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-25"><a href="#cb19-25" aria-hidden="true" tabindex="-1"></a>          <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span><span class="dt">int</span><span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb19-26"><a href="#cb19-26" aria-hidden="true" tabindex="-1"></a>              <span class="kw">static_assert</span><span class="op">(</span><span class="kw">false</span><span class="op">)</span>; <span class="co">// #4</span></span>
<span id="cb19-27"><a href="#cb19-27" aria-hidden="true" tabindex="-1"></a>          <span class="op">}</span></span>
<span id="cb19-28"><a href="#cb19-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-29"><a href="#cb19-29" aria-hidden="true" tabindex="-1"></a>          <span class="cf">return</span> <span class="dv">2</span>;</span>
<span id="cb19-30"><a href="#cb19-30" aria-hidden="true" tabindex="-1"></a>      <span class="op">}()</span></span>
<span id="cb19-31"><a href="#cb19-31" aria-hidden="true" tabindex="-1"></a>    <span class="op">+</span> <span class="op">...</span> <span class="op">+</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb19-32"><a href="#cb19-32" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>The expression <code class="sourceCode cpp">E1</code> (that first
immediately-invoked lambda) is completely non-dependent, no template
packs, no structured binding packs, no packs of any kind. The expression
<code class="sourceCode cpp">E2</code> is an abridged version of the
previous example’s lambda - it does depend on the structured binding
pack <code class="sourceCode cpp">i</code>.</p>
<p>The intent is that the <code class="sourceCode cpp"><span class="kw">static_assert</span></code>
declarations in
<code class="sourceCode cpp"><span class="pp">#1</span></code> and
<code class="sourceCode cpp"><span class="pp">#3</span></code> do not
fire (since <code class="sourceCode cpp">i</code> is not an empty pack
and neither
<code class="sourceCode cpp"><span class="dt">int</span></code> nor
<code class="sourceCode cpp"><span class="dt">long</span></code> has
larger size than
<code class="sourceCode cpp"><span class="dt">long</span></code>), and
this matches user expectation. The <code class="sourceCode cpp"><span class="kw">static_assert</span></code> in
<code class="sourceCode cpp"><span class="pp">#2</span></code>, if
written in a regular function, would immediately fire - since it’s not
guarded by any kind of template. So the questions are:</p>
<ol type="1">
<li>Does <code class="sourceCode cpp"><span class="pp">#2</span></code>
still fire in this context, or does it become attached to the pack
somehow?</li>
<li>Does <code class="sourceCode cpp"><span class="pp">#4</span></code>
still fire in this context? It’s still exactly as non-dependent as it
was before, but now it’s in a context that’s at least somewhat dependent
- since we’re in a pack expansion over
<code class="sourceCode cpp"><span class="op">...</span>i</code></li>
</ol>
<p>This brings up the question of what the boundary of dependence
is.</p>
<h3 data-number="3.4.3" id="more-templates"><span class="header-section-number">3.4.3</span> More Templates<a href="#more-templates" class="self-link"></a></h3>
<p>The approach suggested by John Spicer is as follows. Consider this
example (let <code class="sourceCode cpp">s<sub>i</sub></code> just be
some statements):</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">()</span> <span class="op">{</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[...</span>xs<span class="op">]</span> <span class="op">=</span> C<span class="op">()</span>;</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>    s<sub>0</sub>;</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>    s<sub>1</sub>;</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>    s<sub>2</sub>;</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Those statements get treated roughly as if they appeared in this
context:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">()</span> <span class="op">{</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[...</span>xs<span class="op">]</span> <span class="op">=</span> C<span class="op">()</span>;</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>    <span class="op">[&amp;](</span><span class="kw">auto</span><span class="op">...</span> xs<span class="op">){</span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>        s<sub>0</sub>;</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>        s<sub>1</sub>;</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>        s<sub>2</sub>;</span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}(</span>xs<span class="op">...)</span>;</span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Of course, not exactly like that (we’re not literally introducing a
generic lambda, there’s no added function scope, all of these statements
are directly in <code class="sourceCode cpp">foo</code> so that
<code class="sourceCode cpp"><span class="cf">return</span></code>s
work, etc.). But this is the model: a structured binding pack, if not
already a templated entity, introduces an <em>implicit template
region</em>.</p>
<p>Importantly, it helps answer all of the questions in the previous
examples: do the <code class="sourceCode cpp"><span class="kw">static_assert</span></code>s
fire in the <a href="#the-varna-example">Varna example addendum</a>? No,
none of them fire.</p>
<h2 data-number="3.5" id="namespace-scope-packs"><span class="header-section-number">3.5</span> Namespace-scope packs<a href="#namespace-scope-packs" class="self-link"></a></h2>
<p>In addition to non-dependent packs, this paper also seems like it
would offer the ability to declare a pack at <em>namespace</em>
scope:</p>
<blockquote>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Point <span class="op">{</span> <span class="dt">int</span> x, y; <span class="op">}</span>;</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="op">[...</span> parts<span class="op">]</span> <span class="op">=</span> Point<span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>Structured bindings in namespace scope are a little odd to begin
with, since they currently cannot be declared
<code class="sourceCode cpp"><span class="kw">inline</span></code>. A
structured binding pack at namespace scope adds that much more
complexity.</p>
<p>Now, EWG originally <a href="https://github.com/cplusplus/papers/issues/294#issuecomment-1234578812">voted
to remove this restriction</a> in a telecon - on the basis that it
seemed like an artificial restriction and that the rules for how to use
this feature should be uniform across all uses of structured bindings.
However, during Core wording review of this paper in the Tokyo meeting,
a lot of issues with this approach surfaced.</p>
<p>Introducing a structured binding pack into a function makes the
region of that function into a template. This has consequences, but
those consequences are localized to <em>just</em> the part of
<em>that</em> function that follows the structured binding
declaration.</p>
<p>Introducing a structured binding pack at namespace scope makes
<em>your entire program</em> into a template. With enormous downstream
consequences. Because unlike a function where we have a clear end to the
region (the end of the block scope), even closing the namespace isn’t
sufficient because the namespace could still be reopened again later!
Code that you have in one header could <em>change lookup rules</em> if
it is included after another header that happened to add a
namespace-scope pack. Even if your header never referenced that pack. If
you had any non-depenent <code class="sourceCode cpp"><span class="cf">if</span> <span class="kw">constexpr</span></code>
conditions, they suddenly become dependent, and those bodies suddenly
can become discarded.</p>
<p>Perhaps there is a way to divine some way to word this feature such
that this doesn’t happen, but that seems to be a very large amount of
work necessary that far exceeds the potential utility thereof. It is not
clear if anybody wants this, and it certainly does not seem worth
delaying this paper further to attempt to add support for it.</p>
<p>Thus, this paper proposes that structured binding packs be limited to
block scope. This decision was confirmed with EWG at the <a href="https://github.com/cplusplus/papers/issues/294#issuecomment-2014848854">Tokyo
meeting</a>.</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.6 <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="cb23"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="st">- <em>attributed-identifier</em>:</span></span>
<span id="cb23-2"><a href="#cb23-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="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="va">+ <em>sb-identifier</em>:</span></span>
<span id="cb23-4"><a href="#cb23-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="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="va">+</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a><span class="st">- <em>attributed-identifier-list</em>:</span></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a><span class="st">-     <em>attributed-identifier</em></span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a><span class="st">-     <em>attributed-identifier-list</em>, <em>attributed-identifier</em></span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="va">+ <em>sb-identifier-list</em>:</span></span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a><span class="va">+     <em>sb-identifier</em></span></span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a><span class="va">+     <em>sb-identifier-list</em>, <em>sb-identifier</em></span></span>
<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a>  <em>structured-binding-declaration</em>:</span>
<span id="cb23-14"><a href="#cb23-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="cb23-15"><a href="#cb23-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 inhabit a block
scope.</span></p>
</blockquote>
</div>
<p>Extend <span>9.3.4.6 <a href="https://wg21.link/dcl.fct">[dcl.fct]</a></span>/5:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">5</a></span>
The type of a function is determined using the following rules. The type
of each parameter (including function parameter packs), is determined
from its own <em>parameter-declaration</em> ([dcl.decl]). After
determining the type of each parameter, any parameter of type “array of
T” or of function type T is adjusted to be “pointer to T”. After
producing the list of parameter types, any top-level cv-qualifiers
modifying a parameter type are deleted when forming the function type.
The resulting list of transformed parameter types and the presence or
absence of the ellipsis or a function parameter pack is the function’s
parameter-type-list.</p>
<p>[Note 3: This transformation does not affect the types of the
parameters. For example, <code class="sourceCode cpp"><span class="dt">int</span><span class="op">(*)(</span><span class="kw">const</span> <span class="dt">int</span> p, <span class="kw">decltype</span><span class="op">(</span>p<span class="op">)*)</span></code>
and <code class="sourceCode cpp"><span class="dt">int</span><span class="op">(*)(</span><span class="dt">int</span>, <span class="kw">const</span> <span class="dt">int</span><span class="op">*)</span></code>
are identical types. — end note]</p>
<div class="example">
<span>[ <em>Example 1:</em> </span>
<div>
<div class="sourceCode" id="cb24"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a>  void f(char*);                  // #1</span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>  void f(char[]) {}               // defines #1</span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>  void f(const char*) {}          // OK, another overload</span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>  void f(char *const) {}          // error: redefines #1</span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>  void g(char(*)[2]);             // #2</span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a>  void g(char[3][2]) {}           // defines #2</span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a>  void g(char[3][3]) {}           // OK, another overload</span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a>  void h(int x(const int));       // #3</span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a>  void h(int (*)(int)) {}         // defines #3</span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a><span class="va">+ void k(int, int);               // #4</span></span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a><span class="va">+ void m() {</span></span>
<span id="cb24-15"><a href="#cb24-15" aria-hidden="true" tabindex="-1"></a><span class="va">+   struct C { int i, j; };</span></span>
<span id="cb24-16"><a href="#cb24-16" aria-hidden="true" tabindex="-1"></a><span class="va">+   auto [... elems] = C{};</span></span>
<span id="cb24-17"><a href="#cb24-17" aria-hidden="true" tabindex="-1"></a><span class="va">+   void k(decltype(elems)...);   // redeclares #4</span></span>
<span id="cb24-18"><a href="#cb24-18" 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 1:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">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"><i>sb-identifier-list</i></span> as names
([basic.scope.declarative]) <span class="rm" style="color: #bf0303"><del>of <em>structured
bindings</em></del></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 structured binding so introduced. <span class="addu">An <em>sb-identifier</em> that contains an ellipsis
introduces a structured binding pack ([temp.variadic]). A <em>structured
binding</em> is either an <em>sb-identifier</em> that does not contain
an ellipsis or an element of a structured binding pack.</span> Let
<i>cv</i> denote the <i>cv-qualifiers</i> in the <i>decl-specifier-seq</i>.</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_5" id="pnum_5">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 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 <em>sb-identifier-list</em>; the
number of non-pack elements shall be no more than the structured binding
size of <code class="sourceCode cpp">E</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">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 2:</em> </span>
<div class="sourceCode" id="cb25"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a>struct C { int x, y, z; };</span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-3"><a href="#cb25-3" 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="cb25-4"><a href="#cb25-4" 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="cb25-5"><a href="#cb25-5" 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="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a>auto [h, i, j, ...k] = C(); // OK, the pack k is empty</span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a>auto [l, m, n, o, ...p] = C(); // error: structured binding size is too small</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_7" id="pnum_7">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 3:</em> </span>
<div>
<div class="sourceCode" id="cb26"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a>auto f() -&gt; int(&amp;)[2];</span>
<span id="cb26-2"><a href="#cb26-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="cb26-3"><a href="#cb26-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="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a><span class="va">+ auto g() -&gt; int(&amp;)[4];</span></span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a><span class="va">+ auto [a, ...b, c] = g();      // a names the first element of the array, b is a pack referring to the second and</span></span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a><span class="va">+                               // third elements, and c names the fourth element</span></span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a><span class="va">+ auto&amp; [...e] = g();           // e is a pack referring to the four elements of the array</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_8" id="pnum_8">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_9" id="pnum_9">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>Change <span>13.1 <a href="https://wg21.link/temp.pre">[temp.pre]</a></span>/8 to extend the
notion of what is a templated entity, first introducing the term
<em>implicit template region</em>:</p>
<div class="std">
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">7a</a></span>
An <em>implicit template region</em> is a subregion of a block scope. An
implicit template region is a template definition. At the end of an
implicit template region, it is immediately instantiated ([temp.pre]). A
declaration of a structured binding pack ([dcl.struct.bind]) that is not
a templated entity (see below) introduces an implicit template region
that includes the declaration of the structured binding pack and ends at
the end of the scope that the structured binding declaration
inhabits.</p>
</div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">8</a></span>
An entity is <em>templated</em> if it is</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">(8.1)</a></span>
a template,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">(8.2)</a></span>
an entity defined ([basic.def]) or created ([class.temporary]) in a
templated entity,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">(8.3)</a></span>
a member of a templated entity,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">(8.4)</a></span>
an enumerator for an enumeration that is a templated entity, <span class="rm" style="color: #bf0303"><del>or</del></span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">(8.5)</a></span>
the closure type of a lambda-expression ([expr.prim.lambda.closure])
appearing in the declaration of a templated entity<span class="rm" style="color: #bf0303"><del>.</del></span> <span class="addu">,
or</span></li>
</ul>
<div class="addu">
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_17" id="pnum_17">(8.6)</a></span>
an entity defined or created within an implicit template region.</li>
</ul>
</div>
<p><span class="note"><span>[ <em>Note 1:</em> </span>A local class, a
local or block variable, or a friend function defined in a templated
entity is a templated entity.<span> — <em>end
note</em> ]</span></span></p>
<div class="addu">
<div class="example">
<p><span>[ <em>Example 4:</em> </span>The following example assumes that
<code class="sourceCode cpp"><span class="dt">char</span></code> and
<code class="sourceCode cpp"><span class="dt">int</span></code> have
different size.</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> C <span class="op">{</span> <span class="dt">char</span> j; <span class="dt">int</span> l; <span class="op">}</span>;</span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> g<span class="op">()</span> <span class="op">{</span></span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span> <span class="op">...</span> i <span class="op">]</span> <span class="op">=</span> C<span class="op">{</span> <span class="ch">&#39;x&#39;</span>, <span class="dv">42</span> <span class="op">}</span>; <span class="co">// #1</span></span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(</span> <span class="op">[</span>c <span class="op">=</span> i<span class="op">]</span> <span class="op">()</span> <span class="op">{</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a>        <span class="co">// The local class L is a templated entity because</span></span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a>        <span class="co">// it is defined within the implicit template region</span></span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a>        <span class="co">// created at #1.</span></span>
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a>        <span class="kw">struct</span> L <span class="op">{</span></span>
<span id="cb27-10"><a href="#cb27-10" aria-hidden="true" tabindex="-1"></a>            <span class="dt">int</span> f<span class="op">()</span> <span class="kw">requires</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span>c<span class="op">)</span> <span class="op">==</span> <span class="dv">1</span><span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="dv">1</span>; <span class="op">}</span></span>
<span id="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a>            <span class="dt">int</span> f<span class="op">()</span> <span class="kw">requires</span> <span class="op">(</span><span class="kw">sizeof</span><span class="op">(</span>c<span class="op">)</span> <span class="op">!=</span> <span class="dv">1</span><span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="dv">2</span>; <span class="op">}</span></span>
<span id="cb27-12"><a href="#cb27-12" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span>;</span>
<span id="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> L<span class="op">{}.</span>f<span class="op">()</span>;</span>
<span id="cb27-14"><a href="#cb27-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span> <span class="op">()</span> <span class="op">+</span> <span class="op">...</span>  <span class="op">+</span> <span class="dv">0</span> <span class="op">)</span>;</span>
<span id="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-17"><a href="#cb27-17" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> v <span class="op">=</span> g<span class="op">()</span>; <span class="co">// OK, v == 3</span></span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
<div class="example">
<span>[ <em>Example 5:</em> </span>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> C <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-3"><a href="#cb28-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="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-5"><a href="#cb28-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="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> f<span class="op">()</span> <span class="op">{</span></span>
<span id="cb28-7"><a href="#cb28-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="cb28-8"><a href="#cb28-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="cb28-9"><a href="#cb28-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="cb28-10"><a href="#cb28-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb28-11"><a href="#cb28-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-12"><a href="#cb28-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="cb28-13"><a href="#cb28-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-14"><a href="#cb28-14" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb28-15"><a href="#cb28-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="cb28-16"><a href="#cb28-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
</div>
</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_18" id="pnum_18">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 6:</em> </span>
<div class="sourceCode" id="cb29"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a>auto foo() -&gt; int(&amp;)[2];</span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a>auto [...a] = foo();          // a is a structured binding pack containing 2 elements</span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a>auto [b, c, ...d] = foo();    // d is a structured binding pack containing 0 elements</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_19" id="pnum_19">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_20" id="pnum_20">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_21" id="pnum_21">(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_22" id="pnum_22">(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_23" id="pnum_23">(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_24" id="pnum_24">(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_25" id="pnum_25">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><span class="marginalizedparent"><a class="marginalized" href="#pnum_26" id="pnum_26">(3.1)</a></span>
associated by name lookup with one or more declarations declared with a
dependent type,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_27" id="pnum_27">(3.2)</a></span>
associated by name lookup with a non-type template-parameter declared
with a type that contains a placeholder type,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_28" id="pnum_28">(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,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_29" id="pnum_29">(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,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_30" id="pnum_30">(3.5)</a></span>
associated by name lookup with a structured binding declaration
([dcl.struct.bind]) whose brace-or-equal-initializer is
type-dependent,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_31" id="pnum_31">(3.5b)</a></span>
<span class="addu">associated by name lookup with a pack, unless that
pack is a non-type template parameter pack whose types are
non-dependent,</span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_32" id="pnum_32">(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]),</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_33" id="pnum_33">(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,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_34" id="pnum_34">(3.8)</a></span>
a conversion-function-id that specifies a dependent type, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_35" id="pnum_35">(3.9)</a></span>
dependent</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_36" id="pnum_36">4</a></span>
Expressions of the following form are value-dependent:</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a>sizeof ... ( identifier )</span>
<span id="cb30-2"><a href="#cb30-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>
<p>Add a new paragraph at the end of <span>13.8.4.1 <a href="https://wg21.link/temp.point">[temp.point]</a></span>:</p>
<div class="std ins">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_37" id="pnum_37">*</a></span>
For an implicit template region, the point of instantiation immediately
follows the namespace scope declaration or definition that encloses the
region.</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="cb31"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="st">- __cpp_­structured_­bindings 201606L</span></span>
<span id="cb31-2"><a href="#cb31-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-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>
