<!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-07-14" />
  <title>Fix submdspan for C++26</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%;}
</style>
  <style>
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { 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 { } 
code span.al { color: #ff0000; } 
code span.an { } 
code span.at { } 
code span.bn { color: #9f6807; } 
code span.bu { color: #9f6807; } 
code span.cf { color: #00607c; } 
code span.ch { color: #9f6807; } 
code span.cn { } 
code span.co { color: #008000; font-style: italic; } 
code span.cv { color: #008000; font-style: italic; } 
code span.do { color: #008000; } 
code span.dt { color: #00607c; } 
code span.dv { color: #9f6807; } 
code span.er { color: #ff0000; font-weight: bold; } 
code span.ex { } 
code span.fl { color: #9f6807; } 
code span.fu { } 
code span.im { } 
code span.in { color: #008000; } 
code span.kw { color: #00607c; } 
code span.op { color: #af1915; } 
code span.ot { } 
code span.pp { color: #6f4e37; } 
code span.re { } 
code span.sc { color: #9f6807; } 
code span.ss { color: #9f6807; } 
code span.st { color: #9f6807; } 
code span.va { } 
code span.vs { color: #9f6807; } 
code span.wa { color: #008000; font-weight: bold; } 
code.diff {color: #898887}
code.diff span.va {color: #00AA00}
code.diff span.st {color: #bf0303}
</style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
}
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; }

div#refs p { padding-left: 32px; text-indent: -32px; }
</style>
  <link href="data:image/vnd.microsoft.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">Fix submdspan for C++26</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #: </td>
    <td>P3355R0</td>
  </tr>
  <tr>
    <td>Date: </td>
    <td>2024-07-14</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project: </td>
    <td>Programming Language C++<br>
      Library Evolution<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to: </td>
    <td>
      Mark Hoemmen<br>&lt;<a href="mailto:mhoemmen@nvidia.com" class="email">mhoemmen@nvidia.com</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</a></li>
<li><a href="#abstract" id="toc-abstract"><span class="toc-section-number">2</span> Abstract</a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">3</span> Motivation</a>
<ul>
<li><a href="#permit-user-defined-pair-types" id="toc-permit-user-defined-pair-types"><span class="toc-section-number">3.1</span> Permit user-defined pair types</a>
<ul>
<li><a href="#requirement-is-currently-an-opt-in-type-list" id="toc-requirement-is-currently-an-opt-in-type-list"><span class="toc-section-number">3.1.1</span> Requirement is currently an
opt-in type list</a></li>
<li><a href="#requirement-should-depend-on-structured-binding-instead" id="toc-requirement-should-depend-on-structured-binding-instead"><span class="toc-section-number">3.1.2</span> Requirement should depend on
structured binding instead</a></li>
<li><a href="#yes-complex-is-a-valid-slice-type-it-already-was" id="toc-yes-complex-is-a-valid-slice-type-it-already-was"><span class="toc-section-number">3.1.3</span> Yes, <code>complex</code> is a
valid slice type; it already was</a></li>
<li><a href="#slice-elements-are-indices-so-they-have-the-same-requirements" id="toc-slice-elements-are-indices-so-they-have-the-same-requirements"><span class="toc-section-number">3.1.4</span> Slice elements are indices, so
they have the same requirements</a></li>
</ul></li>
<li><a href="#preserve-contiguity-with-compile-time-extent" id="toc-preserve-contiguity-with-compile-time-extent"><span class="toc-section-number">3.2</span> Preserve contiguity with
compile-time extent</a>
<ul>
<li><a href="#vectorization-example" id="toc-vectorization-example"><span class="toc-section-number">3.2.1</span> Vectorization example</a></li>
<li><a href="#issues-with-c-working-draft" id="toc-issues-with-c-working-draft"><span class="toc-section-number">3.2.2</span> Issues with C++ Working
Draft</a></li>
<li><a href="#why-we-dont-try-to-fix-aligned_accessoroffset" id="toc-why-we-dont-try-to-fix-aligned_accessoroffset"><span class="toc-section-number">3.2.3</span> Why we don’t try to fix
<code>aligned_accessor::offset</code></a></li>
</ul></li>
</ul></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">4</span> Wording</a></li>
<li><a href="#appendix-a-a-user-defined-pair-type" id="toc-appendix-a-a-user-defined-pair-type"><span class="toc-section-number">5</span> Appendix A: A user-defined pair
type</a></li>
</ul>
</div>
<h1 data-number="1" id="revision-history"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<h1 data-number="2" id="abstract"><span class="header-section-number">2</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>We propose the following fixes to <code>submdspan</code> for
C++26.</p>
<ol type="1">
<li><p>Permit user-defined pair types to be used as slices, rather than
restricting the list to the opt-in set of types in
<strong>[tuple.like]</strong>.</p></li>
<li><p>Change <code>layout_left</code>, <code>layout_right</code>,
<code>layout_left_padded</code>, and <code>layout_right_padded</code> so
that if a slice is <code>strided_slice</code> where
<code>stride_type</code> models
<em><code>integral-constant-like</code></em> and
<code>stride_type::value</code> equals 1, then the same layout mapping
type results as if the slice models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code>.
This lets users express a slice with compile-time extent that does not
cause common layouts to devolve into
<code>layout_stride</code>.</p></li>
</ol>
<h1 data-number="3" id="motivation"><span class="header-section-number">3</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<h2 data-number="3.1" id="permit-user-defined-pair-types"><span class="header-section-number">3.1</span> Permit user-defined pair
types<a href="#permit-user-defined-pair-types" class="self-link"></a></h2>
<h3 data-number="3.1.1" id="requirement-is-currently-an-opt-in-type-list"><span class="header-section-number">3.1.1</span> Requirement is currently an
opt-in type list<a href="#requirement-is-currently-an-opt-in-type-list" class="self-link"></a></h3>
<p>Users sometimes want to express “a pair of integers” using types
other than <code>std::tuple</code> or <code>std::pair</code>. For
example, users might want their representation of a pair of two
<code>integral_constant</code> to be an empty class, but a
<code>std::tuple</code> of two elements is not empty. (This is because
<code>get&lt;0&gt;</code> and <code>get&lt;1&gt;</code> must return
references to their corresponding members.) However, the current
requirements for a <code>submdspan</code> “pair of integers” slice,
<em><code>index-pair-like</code></em>, include
<em><code>pair-like</code></em>. This in turn includes
<em><code>tuple-like</code></em>, an exposition-only concept which is an
opt-in list of types: <code>array</code>, <code>complex</code>,
<code>pair</code>, <code>tuple</code>, or <code>ranges​::​subrange</code>
(see <strong>[tuple.like]</strong>). As a result, a user-defined type
cannot model <em><code>tuple-like</code></em>.</p>
<h3 data-number="3.1.2" id="requirement-should-depend-on-structured-binding-instead"><span class="header-section-number">3.1.2</span> Requirement should depend on
structured binding instead<a href="#requirement-should-depend-on-structured-binding-instead" class="self-link"></a></h3>
<p>The author of this proposal is a coauthor of P2630, and has asked the
other authors of P2630 what they intended. The authors of P2630 always
intended to support user-defined “pair-like” slice types. How they meant
to define “pair-like” is that structured binding works for the slice
type, and results in two elements, each of which is convertible to the
layout mapping’s <code>index_type</code>. We can express “structured
binding works” using the language of
<a href="https://eel.is/c++draft/dcl.struct.bind#4"><strong>[dcl.struct.bind]</strong>
4</a>. The key is that <code>tuple_size_v&lt;T&gt;</code> is a
“well-formed integral constant expression.” If it’s also equal to 2,
then we have a “pair of indices” slice.</p>
<p>That last <code>convertible_to&lt;index_type&gt;</code> requirement
doesn’t just support integers and
<em><code>integral-constant-like</code></em> types; it also supports
more interesting types like “strong typedefs” that wrap integers to give
them meaning. A common use case for integer strong typedefs like this is
to help prevent common bugs like mixing up loop indices. Here is a
somewhat contrived example from the finite-element method for solving
partial differential equations.</p>
<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><span class="cf">for</span> <span class="op">(</span>Element e <span class="op">=</span> <span class="op">{}</span>; e <span class="op">&lt;</span> num_elements; <span class="op">++</span>e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span>FaceOffset fo <span class="op">=</span> faces_begin<span class="op">[</span>e<span class="op">]</span>; fo <span class="op">&lt;</span> faces_end<span class="op">[</span>e<span class="op">]</span>; <span class="op">++</span>fo<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    Face f <span class="op">=</span> faces<span class="op">[</span>fo<span class="op">]</span>; <span class="co">// faces live in a flat array</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">double</span> sum <span class="op">=</span> <span class="fl">0.0</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span>QuadraturePointIndex q <span class="op">=</span> <span class="op">{}</span>; q <span class="op">&lt;</span> num_quadrature_points<span class="op">[</span>f<span class="op">]</span>; <span class="op">++</span>q<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>      <span class="co">// Here, quadrature coefficients are the same for all faces.</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>      sum <span class="op">+=</span> quadrature_coefficient<span class="op">[</span>q<span class="op">]</span> <span class="op">*</span> value_at<span class="op">[</span>quadrature_point_to_vertex<span class="op">(</span>f, q<span class="op">)]</span>;</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>    store_integration_result<span class="op">(</span>f, sum<span class="op">)</span>;</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="3.1.3" id="yes-complex-is-a-valid-slice-type-it-already-was"><span class="header-section-number">3.1.3</span> Yes, <code>complex</code> is
a valid slice type; it already was<a href="#yes-complex-is-a-valid-slice-type-it-already-was" class="self-link"></a></h3>
<ol type="1">
<li><p><code>complex</code> is a valid slice type; it was already before
this proposal.</p></li>
<li><p>We don’t propose to change that here, because it would break
consistency between <code>mdspan</code>’s <code>operator[]</code> and
the index type used by slices.</p></li>
</ol>
<p>Some users might find it surprising that
<code>complex&lt;float&gt;(1.25f, 3.75f)</code> is a valid slice with
the same meaning as <code>tuple&lt;int, int&gt;{1, 4}</code>. This is
true in the current Working Draft, because adoption of
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2819r2.pdf">P2819R2</a>
(“Add tuple protocol to complex”) added <code>complex</code> to the
opt-in list of <em><code>tuple-like</code></em> types. A valid
“pair-like” slice has two requirements:</p>
<ol type="1">
<li><p><em><code>pair-like</code></em> (that is,
<em><code>tuple-like</code></em> with two elements); and</p></li>
<li><p>the elements are (implicitly) convertible to the
<code>mdspan</code>’s <code>index_type</code>.</p></li>
</ol>
<p>The type <code>complex&lt;float&gt;</code> is
<em><code>pair-like</code></em> due to P2819R2’s adoption, and its
element type <code>float</code> is implicitly convertible to
<code>int</code>. Even though this proposal would change the
<em><code>pair-like</code></em> requirement on slices, it would only
strictly enlarge the set of valid slice types.</p>
<h3 data-number="3.1.4" id="slice-elements-are-indices-so-they-have-the-same-requirements"><span class="header-section-number">3.1.4</span> Slice elements are indices,
so they have the same requirements<a href="#slice-elements-are-indices-so-they-have-the-same-requirements" class="self-link"></a></h3>
<p>The <code>convertible_to&lt;index_type&gt;</code> requirement exists
for good reason: it’s the same as the requirement on types that
<code>mdspan</code>’s <code>operator[]</code> accepts. A slice
represents a finite set of indices, and a “pair-like” slice specifically
represents an interval with a finite lower and upper bound, both of
which are indices. <code>x[1.25f]</code> works if <code>x</code> is an
<code>mdspan</code>, an <code>array</code>, a <code>vector</code>, or
even a raw array. Thus, we see no reason why
<code>tuple{1.25f, 3.75f}</code> or even
<code>complex&lt;float&gt;{1.25f, 3.75f}</code> shouldn’t work as a
slice.</p>
<p>One could carve out an exception like “but not
<code>complex&lt;T&gt;</code> for any <code>T</code>.” However, that
would have two issues. First, it would still permit types like
<code>tuple&lt;float&gt;</code>. Second, it would permit user-defined
complex types with floating-point element type, as long as those types
define the tuple protocol. Support for user-defined complex types is a
feature of the linear algebra proposal P1673, which was adopted into the
Working Draft. In general, while we might be able to exclude
<code>complex</code> specifically, we don’t have a way to define the
open-ended set of types that “maybe shouldn’t be treated as pair-like
slices even though this works just fine syntactically.” For this reason,
we do not propose treating <code>complex</code> differently than any
other pair-like type.</p>
<p>If we wanted to carve out an exception like “convertible to
<code>index_type</code>, but not a floating-point type,” then that would
still permit class types that wrap a floating-point number, but are
convertible to an integral type, like this.</p>
<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">struct</span> WrappedFloat <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span> value_;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">operator</span> <span class="dt">int</span><span class="op">()</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> value_;</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Again, we find impossible to define the open-ended set of types that
“maybe shouldn’t be used as array indices.”</p>
<p>The key rule is that the set of types permitted in slices should be
the same as the set of types permitted in
<code>mdspan::operator[]</code>. We should never change those two
requirements separately. This rule would still let us carve out
exceptions for the “pair-like” types themselves (e.g., we could forbid
<code>complex</code>, even though we do not here), but not for the
members of the pair-like types.</p>
<h2 data-number="3.2" id="preserve-contiguity-with-compile-time-extent"><span class="header-section-number">3.2</span> Preserve contiguity with
compile-time extent<a href="#preserve-contiguity-with-compile-time-extent" class="self-link"></a></h2>
<h3 data-number="3.2.1" id="vectorization-example"><span class="header-section-number">3.2.1</span> Vectorization example<a href="#vectorization-example" class="self-link"></a></h3>
<p>Suppose that one wants to vectorize a 1-D array copy operation using
<code>mdspan</code> and <code>aligned_accessor</code> (P2897). One has a
<code>copy_8_floats</code> function that optimizes the special case of
copying a contiguous array of 8 <code>float</code>s, where the start of
the array is aligned to <code>8 * sizeof(float)</code> (32) bytes. In
practice, plenty of libraries exist to optimize 1-D array copy. This is
just an example that simplifies the use cases for explicit 8-wide SIMD
enough to show in a brief proposal.</p>
<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="kw">class</span> ElementType, <span class="dt">size_t</span> ext, <span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_array_view <span class="op">=</span> mdspan<span class="op">&lt;</span>ElementType,</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">&lt;</span><span class="dt">int</span>, ext<span class="op">&gt;</span>, layout_right,</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  aligned_accessor<span class="op">&lt;</span>ElementType, byte_alignment<span class="op">&gt;&gt;</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="dt">void</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>copy_8_floats<span class="op">(</span>aligned_array_view<span class="op">&lt;</span><span class="kw">const</span> <span class="dt">float</span>, <span class="dv">8</span>, <span class="dv">32</span><span class="op">&gt;</span> src,</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  aligned_array_view<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span>, <span class="dv">32</span><span class="op">&gt;</span> dst<span class="op">)</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>  <span class="co">// One would instead use a hardware instruction for aligned copy,</span></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">// or a &quot;simd&quot; or &quot;unroll&quot; pragma.</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> <span class="dv">8</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>    dst<span class="op">[</span>k<span class="op">]</span> <span class="op">=</span> src<span class="op">[</span>k<span class="op">]</span>;</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The natural next step would be to use <code>copy_8_floats</code> to
implement copying 1-D <code>float</code> arrays by the usual
“strip-mining” approach.</p>
<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><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> array_view <span class="op">=</span> mdspan<span class="op">&lt;</span>ElementType, dims<span class="op">&lt;</span><span class="dv">1</span>, <span class="dt">int</span><span class="op">&gt;&gt;</span>;</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> slow_copy<span class="op">(</span>array_view<span class="op">&lt;</span><span class="kw">const</span> <span class="dt">float</span><span class="op">&gt;</span> src, array_view<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;</span> dst<span class="op">)</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>src<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> dst<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> src<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    dst<span class="op">[</span>k<span class="op">]</span> <span class="op">=</span> src<span class="op">[</span>k<span class="op">]</span>;</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> vector_length<span class="op">&gt;</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> strip_mined_copy<span class="op">(</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>  aligned_array_view<span class="op">&lt;</span><span class="kw">const</span> <span class="dt">float</span>, dynamic_extent,</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>    vector_length <span class="op">*</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">float</span><span class="op">)&gt;</span> src,</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>  aligned_array_view<span class="op">&lt;</span>      <span class="dt">float</span>, dynamic_extent,</span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>    vector_length <span class="op">*</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">float</span><span class="op">)&gt;</span> dst<span class="op">)</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>src<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> dst<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>src<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">%</span> vector_length <span class="op">==</span> <span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> beg <span class="op">=</span> <span class="dv">0</span>; beg <span class="op">&lt;</span> src<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; beg <span class="op">+=</span> vector_length<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> one <span class="op">=</span> std<span class="op">::</span>integral_constant<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">1</span><span class="op">&gt;{}</span>;</span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> vec_len <span class="op">=</span> std<span class="op">::</span>integral_constant<span class="op">&lt;</span><span class="dt">int</span>, vector_length<span class="op">&gt;{}</span>;</span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Using strided_slice lets the extent be a compile-time constant.</span></span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a>    <span class="co">// tuple{beg, beg + vector_length} would result in dynamic_extent.</span></span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> vector_slice <span class="op">=</span></span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a>      strided_slice<span class="op">{.</span>offset<span class="op">=</span>dst_lower, <span class="op">.</span>extent<span class="op">=</span>vector_length, <span class="op">.</span>stride<span class="op">=</span>one<span class="op">}</span>;</span>
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a>    <span class="co">// PROBLEM: Current wording makes this always layout_stride,</span></span>
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a>    <span class="co">// but we know that it could be layout_right.</span></span>
<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> src_slice <span class="op">=</span> submdspan<span class="op">(</span>src, vector_slice<span class="op">)</span>;</span>
<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> dst_slice <span class="op">=</span> submdspan<span class="op">(</span>dst, vector_slice<span class="op">)</span>;</span>
<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a>    copy_8_floats<span class="op">(</span>src_slice, dst_slice<span class="op">)</span>;</span>
<span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-39"><a href="#cb4-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-40"><a href="#cb4-40" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> copy<span class="op">(</span>array_view<span class="op">&lt;</span><span class="kw">const</span> <span class="dt">float</span><span class="op">&gt;</span> src, array_view<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;</span> dst<span class="op">)</span></span>
<span id="cb4-41"><a href="#cb4-41" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb4-42"><a href="#cb4-42" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>src<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> dst<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb4-43"><a href="#cb4-43" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">int</span> vector_length <span class="op">=</span> <span class="dv">8</span>;</span>
<span id="cb4-44"><a href="#cb4-44" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-45"><a href="#cb4-45" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Handle possibly unaligned prefix of less than vector_length elements. </span></span>
<span id="cb4-46"><a href="#cb4-46" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> aligned_starting_index <span class="op">=</span> <span class="op">[](</span><span class="kw">auto</span><span class="op">*</span> ptr<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-47"><a href="#cb4-47" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> v <span class="op">=</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">unsigned</span><span class="op">&gt;(</span>vector_length<span class="op">)</span>;</span>
<span id="cb4-48"><a href="#cb4-48" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> ptr_value <span class="op">=</span> <span class="kw">reinterpret_cast</span><span class="op">&lt;</span><span class="dt">uintptr_t</span><span class="op">&gt;(</span>ptr_value<span class="op">)</span>;</span>
<span id="cb4-49"><a href="#cb4-49" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> remainder <span class="op">=</span> ptr_value <span class="op">%</span> v;</span>
<span id="cb4-50"><a href="#cb4-50" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;(</span>ptr_value <span class="op">+</span> <span class="op">(</span>v <span class="op">-</span> remainder<span class="op">)</span> <span class="op">%</span> v<span class="op">)</span>;</span>
<span id="cb4-51"><a href="#cb4-51" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb4-52"><a href="#cb4-52" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> src_beg <span class="op">=</span> aligned_starting_index<span class="op">(</span>src<span class="op">.</span>data<span class="op">())</span>;</span>
<span id="cb4-53"><a href="#cb4-53" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> dst_beg <span class="op">=</span> aligned_starting_index<span class="op">(</span>dst<span class="op">.</span>data<span class="op">())</span>;</span>
<span id="cb4-54"><a href="#cb4-54" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>src_beg <span class="op">!=</span> dst_beg<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-55"><a href="#cb4-55" aria-hidden="true" tabindex="-1"></a>    slow_copy<span class="op">(</span>src, dst<span class="op">)</span>;</span>
<span id="cb4-56"><a href="#cb4-56" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span>;</span>
<span id="cb4-57"><a href="#cb4-57" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb4-58"><a href="#cb4-58" aria-hidden="true" tabindex="-1"></a>  slow_copy<span class="op">(</span>submdspan<span class="op">(</span>src, tuple<span class="op">{</span><span class="dv">0</span>, src_beg<span class="op">})</span>,</span>
<span id="cb4-59"><a href="#cb4-59" aria-hidden="true" tabindex="-1"></a>    submdspan<span class="op">(</span>dst, tuple<span class="op">{</span><span class="dv">0</span>, dst_beg<span class="op">}))</span>;</span>
<span id="cb4-60"><a href="#cb4-60" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-61"><a href="#cb4-61" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Strip-mine the aligned vector_length segments of the array.</span></span>
<span id="cb4-62"><a href="#cb4-62" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> src_end <span class="op">=</span> <span class="op">(</span>src<span class="op">.</span>size<span class="op">()</span> <span class="op">/</span> vector_length<span class="op">)</span> <span class="op">*</span> vector_length;</span>
<span id="cb4-63"><a href="#cb4-63" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> dst_end <span class="op">=</span> <span class="op">(</span>dst<span class="op">.</span>size<span class="op">()</span> <span class="op">/</span> vector_length<span class="op">)</span> <span class="op">*</span> vector_length;</span>
<span id="cb4-64"><a href="#cb4-64" aria-hidden="true" tabindex="-1"></a>  strip_mined_copy<span class="op">&lt;</span><span class="dv">8</span><span class="op">&gt;(</span>submdspan<span class="op">(</span>src, tuple<span class="op">{</span>src_beg, src_end<span class="op">})</span>,</span>
<span id="cb4-65"><a href="#cb4-65" aria-hidden="true" tabindex="-1"></a>    submdspan<span class="op">(</span>dst, tuple<span class="op">{</span>dst_beg, dst_end<span class="op">}))</span>;</span>
<span id="cb4-66"><a href="#cb4-66" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-67"><a href="#cb4-67" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Handle suffix of less than vector_length elements.</span></span>
<span id="cb4-68"><a href="#cb4-68" aria-hidden="true" tabindex="-1"></a>  slow_copy<span class="op">(</span>submdspan<span class="op">(</span>src, tuple<span class="op">{</span>src_end, src<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)})</span>,</span>
<span id="cb4-69"><a href="#cb4-69" aria-hidden="true" tabindex="-1"></a>    submdspan<span class="op">(</span>dst, tuple<span class="op">{</span>dst_end, dst<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)}))</span>;</span>
<span id="cb4-70"><a href="#cb4-70" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The <code>strip_mined_copy</code> function must use
<code>strided_slice</code> to get slices of 8 elements at a time, rather
than <code>tuple</code>. This ensures that the resulting extent is a
compile-time constant 8, even though the slice starts at a run-time
index <code>beg</code>.</p>
<h3 data-number="3.2.2" id="issues-with-c-working-draft"><span class="header-section-number">3.2.2</span> Issues with C++ Working
Draft<a href="#issues-with-c-working-draft" class="self-link"></a></h3>
<p>The current C++ Working Draft has two issues that hinder optimization
of the above code.</p>
<ol type="1">
<li><p>The above <code>submdspan</code> results always have
<code>layout_stride</code>, even though we know that they are contiguous
and thus should have <code>layout_right</code>.</p></li>
<li><p>The <code>submdspan</code> operations in
<code>strip_mined_copy</code> should result in
<code>aligned_accessor</code> with 32-byte alignment, but instead give
<code>default_accessor</code>. This is because
<code>aligned_accessor</code>’s <code>offset</code> member function
takes the offset as a <code>size_t</code>. This discards compile-time
information, like knowing that the offset is divisible by some
overalignment factor.</p></li>
</ol>
<p>This proposal fixes (1) for <code>layout_left</code>,
<code>layout_right</code>, <code>layout_left_padded</code>, and
<code>layout_right_padded</code>. We can do that without breaking
changes, because C++26 is still a working draft. This proposal does
<em>not</em> fix (2), because that would require a breaking change to
both the layout mapping requirements and the accessor requirements, and
because it would complicate both of them quite a bit.</p>
<h3 data-number="3.2.3" id="why-we-dont-try-to-fix-aligned_accessoroffset"><span class="header-section-number">3.2.3</span> Why we don’t try to fix
<code>aligned_accessor::offset</code><a href="#why-we-dont-try-to-fix-aligned_accessoroffset" class="self-link"></a></h3>
<p>Regarding (2),
<a href="https://eel.is/c++draft/views.multidim#mdspan.submdspan.submdspan-6"><strong>[mdspan.submdspan.submdspan]</strong>
6</a> says that <code>submdspan(src, slices...)</code> has effects
equivalent to the following.</p>
<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">auto</span> sub_map_offset <span class="op">=</span> submdspan_mapping<span class="op">(</span>src<span class="op">.</span>mapping<span class="op">()</span>, slices<span class="op">...)</span>;</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> mdspan<span class="op">(</span>src<span class="op">.</span>accessor<span class="op">().</span>offset<span class="op">(</span>src<span class="op">.</span>data<span class="op">()</span>, sub_map_offset<span class="op">.</span>offset<span class="op">)</span>,</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>              sub_map_offset<span class="op">.</span>mapping,</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>              AccessorPolicy<span class="op">::</span>offset_policy<span class="op">(</span>src<span class="op">.</span>accessor<span class="op">()))</span>;</span></code></pre></div>
<p>The problem is
<code>AccessorPolicy::offset_policy(src.accessor())</code>. The type
<code>offset_policy</code> is the wrong type in this case,
<code>default_accessor&lt;const float&gt;</code> instead of
<code>aligned_accessor&lt;const float, 32&gt;</code>. If we want an
offset with suitable compile-time alignment to have a different accessor
type, then we would need at least the following changes.</p>
<ol type="1">
<li><p>The Standard Library would need a new type that represents the
product of a compile-time integer (that is, an
<em><code>integral-constant-like</code></em> type) and a “run-time”
integer (an <code>integral</code>-not-<code>bool</code> type). It would
need overloaded arithmetic operators that preserve this product form as
much as possible. For example, <span class="math inline">8<em>x</em> + 4</span> for a run-time integer <span class="math inline"><em>x</em></span> should result in <span class="math inline">4<em>y</em></span> where <span class="math inline"><em>y</em> = 2<em>x</em> + 1</span> is a run-time
integer.</p></li>
<li><p>At least the Standard layout mappings’ <code>operator()</code>
would need to compute with these types and return them if possible. The
layout mapping requirements would thus need to change, as currently
<code>operator()</code> must return <code>index_type</code> (see
<a href="https://eel.is/c++draft/mdspan.layout.reqmts#7"><strong>[[mdspan.layout.reqmts]]</strong>
7</a>).</p></li>
<li><p><code>aligned_accessor::offset</code> would need an overload
taking a type that expresses the product of a compile-time integer (of
suitable alignment) and a run-time integer. The accessor requirements
<a href="https://eel.is/c++draft/mdspan.accessor.reqmts"><strong>[[mdspan.accessor.reqmts]]</strong></a>
may also need to change to permit this.</p></li>
<li><p>The definition of <code>submdspan</code> would need some way to
get the accessor type corresponding to the new <code>offset</code>
overload, instead of <code>aligned_accessor::offset_policy</code> (which
in this case is <code>default_accessor</code>).</p></li>
</ol>
<p>The work-around is to convert the result of <code>submdspan</code> by
hand to use the desired accessor. In the above <code>copy</code>
example, one would replace the line</p>
<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>    copy_8_floats<span class="op">(</span>src_slice, dst_slice<span class="op">)</span>;</span></code></pre></div>
<p>with the following, that depends on <code>aligned_accessor</code>’s
<code>explicit</code> constructor from
<code>default_accessor</code>.</p>
<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>    copy_8_floats<span class="op">(</span>aligned_array_view<span class="op">&lt;</span><span class="kw">const</span> <span class="dt">float</span>, <span class="dv">8</span>, <span class="dv">32</span><span class="op">&gt;{</span>src<span class="op">}</span>,</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>      aligned_array_view<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span>, <span class="dv">32</span><span class="op">&gt;{</span>dst<span class="op">})</span>;</span></code></pre></div>
<p>Given that this work-around is easy to do, should only be needed for
a few special cases, and avoids a big design change to the accessor
policy requirements, we don’t propose trying to fix this issue in the
C++ Working Draft.</p>
<h1 data-number="4" id="wording"><span class="header-section-number">4</span> Wording<a href="#wording" class="self-link"></a></h1>
<blockquote>
<p>Text in blockquotes is not proposed wording, but rather instructions
for generating proposed wording.</p>
</blockquote>
<blockquote>
<p>In <strong>[mdspan.syn]</strong> (“Header <code>&lt;mdspan&gt;</code>
synopsis”), replace the <em><code>index-pair-like</code></em> definition
with the following. (The only line changed is
<em><code>pair-like&lt;T&gt; &amp;&amp;</code></em>.)</p>
</blockquote>
<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> T, <span class="kw">class</span> IndexType<span class="op">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em>index-pair-like</em> <span class="op">=</span>               <span class="co">// exposition only</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>      is_integral_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>tuple_size_v<span class="op">&lt;</span>T<span class="op">&gt;)&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>      <span class="op">(</span>tuple_size_v<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">==</span> <span class="dv">2</span><span class="op">)</span> <span class="op">&amp;&amp;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>      convertible_to<span class="op">&lt;</span>tuple_element_t<span class="op">&lt;</span><span class="dv">0</span>, T<span class="op">&gt;</span>, IndexType<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>      convertible_to<span class="op">&lt;</span>tuple_element_t<span class="op">&lt;</span><span class="dv">1</span>, T<span class="op">&gt;</span>, IndexType<span class="op">&gt;</span>;</span></code></pre></div>
<blockquote>
<p>Throughout <strong>[mdspan.sub]</strong>, wherever the text says</p>
<p>“<span class="math inline"><em>S</em><sub><em>k</em></sub></span>
models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code> or
<code>is_convertible_v&lt;</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>, full_extent_t&gt;</code>
is <code>true</code>,”</p>
<p>replace it with</p>
<p>“<span class="math inline"><em>S</em><sub><em>k</em></sub></span> is
a specialization of <code>strided_slice</code> where
<code>stride_type</code> models
<em><code>integral-constant-like</code></em> and
<code>stride_type::value</code> equals 1, <span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code>, or
<code>is_convertible_v&lt;</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>, full_extent_t&gt;</code>
is <code>true</code>.”</p>
<p>Apply the analogous transformation if the text says <span class="math inline"><em>S</em><sub><em>p</em></sub></span> or <span class="math inline"><em>S</em><sub>0</sub></span>, but is otherwise the
same. Make this set of changes in the following places.</p>
<ul>
<li><p><strong>[mdspan.sub.map.left]</strong> (1.3.2), (1.4), (1.4.1),
and (1.4.3);</p></li>
<li><p><strong>[mdspan.sub.map.right]</strong> (1.3.2), (1.4), (1.4.1),
and (1.4.3);</p></li>
<li><p><strong>[mdspan.sub.map.leftpad]</strong> (1.3.2), (1.4),
(1.4.1), and (1.4.3); and</p></li>
<li><p><strong>[mdspan.sub.map.rightpad]</strong> (1.3.2), (1.4),
(1.4.1), and (1.4.3).</p></li>
</ul>
</blockquote>
<h1 data-number="5" id="appendix-a-a-user-defined-pair-type"><span class="header-section-number">5</span> Appendix A: A user-defined pair
type<a href="#appendix-a-a-user-defined-pair-type" class="self-link"></a></h1>
<p>This section is not normative. It shows an example of a user-defined
pair type <code>user_pair</code> where elements of the pair that are
empty are not stored. This proposal would permit
<code>user_pair&lt;First, Second&gt;</code> to be used as a slice type
with the same meaning as <code>std::tuple&lt;First, Second&gt;</code>.
This <a href="https://godbolt.org/z/K6zYPeG4x">Compiler Explorer
link</a> demonstrates the code below with four compilers: GCC 14.1,
Clang 18.1.0, MSVC v19.40 (VS17.10), and nvc++ 24.5.</p>
<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="pp">#include </span><span class="im">&lt;cassert&gt;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;tuple&gt;</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> std<span class="op">::</span><span class="dt">size_t</span>;</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> user <span class="op">{</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="co">// User-defined pair type that only stores non-empty elements.</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> First, <span class="kw">class</span> Second,</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> FirstIsEmpty <span class="op">=</span> std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>First<span class="op">&gt;</span>,</span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> SecondIsEmpty <span class="op">=</span> std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>Second<span class="op">&gt;&gt;</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> user_pair;</span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> user_pair<span class="op">&lt;</span>First, Second, <span class="kw">true</span>, <span class="kw">true</span><span class="op">&gt;</span> <span class="op">{}</span>;</span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> user_pair<span class="op">&lt;</span>First, Second, <span class="kw">false</span>, <span class="kw">true</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a>  First first;  </span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> user_pair<span class="op">&lt;</span>First, Second, <span class="kw">true</span>, <span class="kw">false</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a>  Second second;</span>
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-28"><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-29"><a href="#cb9-29" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> user_pair<span class="op">&lt;</span>First, Second, <span class="kw">false</span>, <span class="kw">false</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb9-30"><a href="#cb9-30" aria-hidden="true" tabindex="-1"></a>  First first;</span>
<span id="cb9-31"><a href="#cb9-31" aria-hidden="true" tabindex="-1"></a>  Second second;</span>
<span id="cb9-32"><a href="#cb9-32" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-33"><a href="#cb9-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-34"><a href="#cb9-34" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// namespace user</span></span>
<span id="cb9-35"><a href="#cb9-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-36"><a href="#cb9-36" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb9-37"><a href="#cb9-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-38"><a href="#cb9-38" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-39"><a href="#cb9-39" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> tuple_size<span class="op">&lt;</span>user<span class="op">::</span>user_pair<span class="op">&lt;</span>First, Second<span class="op">&gt;&gt;</span></span>
<span id="cb9-40"><a href="#cb9-40" aria-hidden="true" tabindex="-1"></a>  <span class="op">:</span> std<span class="op">::</span>integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">2</span><span class="op">&gt;</span> <span class="op">{}</span>;</span>
<span id="cb9-41"><a href="#cb9-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-42"><a href="#cb9-42" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-43"><a href="#cb9-43" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> tuple_element<span class="op">&lt;</span><span class="dv">0</span>, user<span class="op">::</span>user_pair<span class="op">&lt;</span>First, Second<span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb9-44"><a href="#cb9-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> type <span class="op">=</span> First;</span>
<span id="cb9-45"><a href="#cb9-45" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-46"><a href="#cb9-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-47"><a href="#cb9-47" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-48"><a href="#cb9-48" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> tuple_element<span class="op">&lt;</span><span class="dv">1</span>, user<span class="op">::</span>user_pair<span class="op">&lt;</span>First, Second<span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb9-49"><a href="#cb9-49" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> type <span class="op">=</span> Second;</span>
<span id="cb9-50"><a href="#cb9-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb9-51"><a href="#cb9-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-52"><a href="#cb9-52" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// namespace std</span></span>
<span id="cb9-53"><a href="#cb9-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-54"><a href="#cb9-54" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> Index, <span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-55"><a href="#cb9-55" aria-hidden="true" tabindex="-1"></a><span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> get<span class="op">(</span><span class="kw">const</span> user<span class="op">::</span>user_pair<span class="op">&lt;</span>First, Second<span class="op">&gt;&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-56"><a href="#cb9-56" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>Index <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-57"><a href="#cb9-57" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>First<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb9-58"><a href="#cb9-58" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> First<span class="op">{}</span>;</span>
<span id="cb9-59"><a href="#cb9-59" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-60"><a href="#cb9-60" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb9-61"><a href="#cb9-61" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">const</span> First<span class="op">&amp;&gt;(</span>t<span class="op">.</span>first<span class="op">)</span>;  </span>
<span id="cb9-62"><a href="#cb9-62" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-63"><a href="#cb9-63" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-64"><a href="#cb9-64" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>Index <span class="op">==</span> <span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-65"><a href="#cb9-65" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>Second<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb9-66"><a href="#cb9-66" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> Second<span class="op">{}</span>;</span>
<span id="cb9-67"><a href="#cb9-67" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-68"><a href="#cb9-68" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb9-69"><a href="#cb9-69" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">const</span> Second<span class="op">&amp;&gt;(</span>t<span class="op">.</span>second<span class="op">)</span>;  </span>
<span id="cb9-70"><a href="#cb9-70" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-71"><a href="#cb9-71" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-72"><a href="#cb9-72" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb9-73"><a href="#cb9-73" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>Index <span class="op">&lt;</span> <span class="dv">2</span><span class="bu">u</span><span class="op">)</span>;</span>
<span id="cb9-74"><a href="#cb9-74" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-75"><a href="#cb9-75" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb9-76"><a href="#cb9-76" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-77"><a href="#cb9-77" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> Index, <span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-78"><a href="#cb9-78" aria-hidden="true" tabindex="-1"></a><span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> get<span class="op">(</span>user<span class="op">::</span>user_pair<span class="op">&lt;</span>First, Second<span class="op">&gt;&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-79"><a href="#cb9-79" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>Index <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-80"><a href="#cb9-80" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>First<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb9-81"><a href="#cb9-81" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> First<span class="op">{}</span>;</span>
<span id="cb9-82"><a href="#cb9-82" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-83"><a href="#cb9-83" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb9-84"><a href="#cb9-84" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span>First<span class="op">&amp;&gt;(</span>t<span class="op">.</span>first<span class="op">)</span>;  </span>
<span id="cb9-85"><a href="#cb9-85" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-86"><a href="#cb9-86" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-87"><a href="#cb9-87" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>Index <span class="op">==</span> <span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-88"><a href="#cb9-88" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>Second<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb9-89"><a href="#cb9-89" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> Second<span class="op">{}</span>;</span>
<span id="cb9-90"><a href="#cb9-90" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-91"><a href="#cb9-91" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb9-92"><a href="#cb9-92" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> <span class="kw">static_cast</span><span class="op">&lt;</span>Second<span class="op">&amp;&gt;(</span>t<span class="op">.</span>second<span class="op">)</span>;  </span>
<span id="cb9-93"><a href="#cb9-93" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-94"><a href="#cb9-94" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-95"><a href="#cb9-95" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb9-96"><a href="#cb9-96" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>Index <span class="op">&lt;</span> <span class="dv">2</span><span class="bu">u</span><span class="op">)</span>;</span>
<span id="cb9-97"><a href="#cb9-97" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-98"><a href="#cb9-98" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb9-99"><a href="#cb9-99" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-100"><a href="#cb9-100" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> Index, <span class="kw">class</span> First, <span class="kw">class</span> Second<span class="op">&gt;</span></span>
<span id="cb9-101"><a href="#cb9-101" aria-hidden="true" tabindex="-1"></a><span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> get<span class="op">(</span>user<span class="op">::</span>user_pair<span class="op">&lt;</span>First, Second<span class="op">&gt;&amp;&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-102"><a href="#cb9-102" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>Index <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-103"><a href="#cb9-103" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>First<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb9-104"><a href="#cb9-104" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> First<span class="op">{}</span>;</span>
<span id="cb9-105"><a href="#cb9-105" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-106"><a href="#cb9-106" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb9-107"><a href="#cb9-107" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> std<span class="op">::</span>move<span class="op">(</span>t<span class="op">.</span>first<span class="op">)</span>;  </span>
<span id="cb9-108"><a href="#cb9-108" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-109"><a href="#cb9-109" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-110"><a href="#cb9-110" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>Index <span class="op">==</span> <span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-111"><a href="#cb9-111" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>Second<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb9-112"><a href="#cb9-112" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> Second<span class="op">{}</span>;</span>
<span id="cb9-113"><a href="#cb9-113" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-114"><a href="#cb9-114" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb9-115"><a href="#cb9-115" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> std<span class="op">::</span>move<span class="op">(</span>t<span class="op">.</span>second<span class="op">)</span>;  </span>
<span id="cb9-116"><a href="#cb9-116" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-117"><a href="#cb9-117" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-118"><a href="#cb9-118" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb9-119"><a href="#cb9-119" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>Index <span class="op">&lt;</span> <span class="dv">2</span><span class="bu">u</span><span class="op">)</span>;</span>
<span id="cb9-120"><a href="#cb9-120" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-121"><a href="#cb9-121" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb9-122"><a href="#cb9-122" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-123"><a href="#cb9-123" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> Value<span class="op">&gt;</span></span>
<span id="cb9-124"><a href="#cb9-124" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Empty <span class="op">{}</span>;</span>
<span id="cb9-125"><a href="#cb9-125" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-126"><a href="#cb9-126" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb9-127"><a href="#cb9-127" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>Empty<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;&gt;)</span>;</span>
<span id="cb9-128"><a href="#cb9-128" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>Empty<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;&gt;)</span>;</span>
<span id="cb9-129"><a href="#cb9-129" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_empty_v<span class="op">&lt;</span>user<span class="op">::</span>user_pair<span class="op">&lt;</span>Empty<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, Empty<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;&gt;&gt;)</span>;</span>
<span id="cb9-130"><a href="#cb9-130" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-131"><a href="#cb9-131" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> type <span class="op">=</span> user<span class="op">::</span>user_pair<span class="op">&lt;</span><span class="dt">int</span>, Empty<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;&gt;</span>;</span>
<span id="cb9-132"><a href="#cb9-132" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-133"><a href="#cb9-133" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>std<span class="op">::</span>tuple_size_v<span class="op">&lt;</span>type<span class="op">&gt;)</span>, <span class="kw">const</span> <span class="dt">size_t</span><span class="op">&gt;)</span>;</span>
<span id="cb9-134"><a href="#cb9-134" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span>std<span class="op">::</span>tuple_element_t<span class="op">&lt;</span><span class="dv">0</span>, type<span class="op">&gt;</span>, <span class="dt">int</span><span class="op">&gt;)</span>;</span>
<span id="cb9-135"><a href="#cb9-135" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span>std<span class="op">::</span>tuple_element_t<span class="op">&lt;</span><span class="dv">1</span>, type<span class="op">&gt;</span>, Empty<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;&gt;)</span>;</span>
<span id="cb9-136"><a href="#cb9-136" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-137"><a href="#cb9-137" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb9-138"><a href="#cb9-138" aria-hidden="true" tabindex="-1"></a>    type t<span class="op">{</span><span class="dv">1</span><span class="op">}</span>;</span>
<span id="cb9-139"><a href="#cb9-139" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>t<span class="op">))</span>, <span class="dt">int</span><span class="op">&amp;&gt;)</span>;</span>
<span id="cb9-140"><a href="#cb9-140" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;(</span>t<span class="op">))</span>, Empty<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;&gt;)</span>;</span>
<span id="cb9-141"><a href="#cb9-141" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>t<span class="op">)</span> <span class="op">==</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb9-142"><a href="#cb9-142" aria-hidden="true" tabindex="-1"></a>    get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>t<span class="op">)</span> <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb9-143"><a href="#cb9-143" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>t<span class="op">)</span> <span class="op">==</span> <span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb9-144"><a href="#cb9-144" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-145"><a href="#cb9-145" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb9-146"><a href="#cb9-146" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> type t<span class="op">{</span><span class="dv">1</span><span class="op">}</span>;</span>
<span id="cb9-147"><a href="#cb9-147" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>t<span class="op">))</span>, <span class="kw">const</span> <span class="dt">int</span><span class="op">&amp;&gt;)</span>;</span>
<span id="cb9-148"><a href="#cb9-148" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;(</span>t<span class="op">))</span>, Empty<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;&gt;)</span>;</span>
<span id="cb9-149"><a href="#cb9-149" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>t<span class="op">)</span> <span class="op">==</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb9-150"><a href="#cb9-150" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-151"><a href="#cb9-151" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb9-152"><a href="#cb9-152" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>type<span class="op">{</span><span class="dv">1</span><span class="op">}))</span>, <span class="dt">int</span><span class="op">&amp;&amp;&gt;)</span>;</span>
<span id="cb9-153"><a href="#cb9-153" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;(</span>type<span class="op">{</span><span class="dv">1</span><span class="op">}))</span>, Empty<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;&gt;)</span>;</span>
<span id="cb9-154"><a href="#cb9-154" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span>get<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;(</span>type<span class="op">{</span><span class="dv">1</span><span class="op">})</span> <span class="op">==</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb9-155"><a href="#cb9-155" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-156"><a href="#cb9-156" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-157"><a href="#cb9-157" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb9-158"><a href="#cb9-158" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
</div>
</body>
</html>
