<!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="2023-06-16" />
  <title>Submdspan</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 { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
  { counter-reset: source-line 0; }
pre.numberSource code > span
  { position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
  { content: counter(source-line);
    position: relative; left: -1em; text-align: right; vertical-align: baseline;
    border: none; display: inline-block;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
    color: #aaaaaa;
  }
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
div.sourceCode
  {  background-color: #f6f8fa; }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span { } /* Normal */
code span.al { color: #ff0000; } /* Alert */
code span.an { } /* Annotation */
code span.at { } /* Attribute */
code span.bn { color: #9f6807; } /* BaseN */
code span.bu { color: #9f6807; } /* BuiltIn */
code span.cf { color: #00607c; } /* ControlFlow */
code span.ch { color: #9f6807; } /* Char */
code span.cn { } /* Constant */
code span.co { color: #008000; font-style: italic; } /* Comment */
code span.cv { color: #008000; font-style: italic; } /* CommentVar */
code span.do { color: #008000; } /* Documentation */
code span.dt { color: #00607c; } /* DataType */
code span.dv { color: #9f6807; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #9f6807; } /* Float */
code span.fu { } /* Function */
code span.im { } /* Import */
code span.in { color: #008000; } /* Information */
code span.kw { color: #00607c; } /* Keyword */
code span.op { color: #af1915; } /* Operator */
code span.ot { } /* Other */
code span.pp { color: #6f4e37; } /* Preprocessor */
code span.re { } /* RegionMarker */
code span.sc { color: #9f6807; } /* SpecialChar */
code span.ss { color: #9f6807; } /* SpecialString */
code span.st { color: #9f6807; } /* String */
code span.va { } /* Variable */
code span.vs { color: #9f6807; } /* VerbatimString */
code span.wa { color: #008000; font-weight: bold; } /* Warning */
code.diff {color: #898887}
code.diff span.va {color: #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"><code>Submdspan</code></h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #: </td>
    <td>P2630R4</td>
  </tr>
  <tr>
    <td>Date: </td>
    <td>2023-06-16</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project: </td>
    <td>Programming Language C++<br>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to: </td>
    <td>
      Christian Trott<br>&lt;<a href="mailto:crtrott@sandia.gov" class="email">crtrott@sandia.gov</a>&gt;<br>
      Damien Lebrun-Grandie<br>&lt;<a href="mailto:lebrungrandt@ornl.gov" class="email">lebrungrandt@ornl.gov</a>&gt;<br>
      Mark Hoemmen<br>&lt;<a href="mailto:mhoemmen@nvidia.com" class="email">mhoemmen@nvidia.com</a>&gt;<br>
      Nevin Liber<br>&lt;<a href="mailto:nliber@anl.gov" class="email">nliber@anl.gov</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"><span class="toc-section-number">1</span> Revision History<span></span></a>
<ul>
<li><a href="#revision-4"><span class="toc-section-number">1.1</span>
Revision 4:<span></span></a></li>
<li><a href="#revision-3-mailing-2023-03"><span class="toc-section-number">1.2</span> Revision 3: Mailing
2023-03<span></span></a></li>
<li><a href="#revision-2-mailing-2023-01"><span class="toc-section-number">1.3</span> Revision 2: Mailing
2023-01<span></span></a></li>
<li><a href="#revision-1-mailing-2022-10"><span class="toc-section-number">1.4</span> Revision 1: Mailing
2022-10<span></span></a></li>
<li><a href="#initial-version-2022-08-mailing"><span class="toc-section-number">1.5</span> Initial Version 2022-08
Mailing<span></span></a></li>
</ul></li>
<li><a href="#description"><span class="toc-section-number">2</span>
Description<span></span></a>
<ul>
<li><a href="#design-of-submdspan"><span class="toc-section-number">2.1</span> Design of
<code>submdspan</code><span></span></a>
<ul>
<li><a href="#slice-specifiers"><span class="toc-section-number">2.1.1</span> Slice
Specifiers<span></span></a></li>
<li><a href="#customization-points"><span class="toc-section-number">2.1.2</span> Customization
Points<span></span></a></li>
<li><a href="#pure-adl-vs.-cpo-vs.-tag-invoke"><span class="toc-section-number">2.1.3</span> Pure ADL vs. CPO vs. tag
invoke<span></span></a></li>
<li><a href="#making-sure-submdspan-behavior-meets-expectations"><span class="toc-section-number">2.1.4</span> Making sure submdspan behavior
meets expectations<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#wording"><span class="toc-section-number">3</span>
Wording<span></span></a>
<ul>
<li><a href="#modify-first-sentence-in-paragraph-3-of-contents-16.4.2.2-to-be"><span class="toc-section-number">3.1</span> Modify first sentence in paragraph
3 of [contents] (16.4.2.2) to be:<span></span></a></li>
<li><a href="#modify-last-sentence-in-paragraph-3-of-contents-16.4.2.2-to-be"><span class="toc-section-number">3.2</span> Modify last sentence in paragraph
3 of [contents] (16.4.2.2) to be:<span></span></a></li>
<li><a href="#add-inside-namespace-std-at-the-end-of-synopsis-in-subsection-24.7.3.2-mdspan.syn"><span class="toc-section-number">3.3</span> Add inside namespace std at the
end of synopsis in subsection 24.7.3.2
[mdspan.syn]<span></span></a></li>
<li><a href="#add-at-the-end-of-the-layout_leftmapping-definition-in-mdspan.layout.left.overview-after-the-private-access-specificer"><span class="toc-section-number">3.4</span> Add at the end of the
<code>layout_left::mapping</code> definition in
[mdspan.layout.left.overview] after the <code>private:</code> access
specificer:<span></span></a></li>
<li><a href="#add-at-the-end-of-the-layout_rightmapping-definition-in-mdspan.layout.right.overview-after-the-private-access-specificer"><span class="toc-section-number">3.5</span> Add at the end of the
<code>layout_right:mapping</code> definition in
[mdspan.layout.right.overview] after the <code>private:</code> access
specificer:<span></span></a></li>
<li><a href="#add-at-the-end-of-the-layout_stridemapping-definition-in-mdspan.layout.stride.overview-after-the-private-access-specificer"><span class="toc-section-number">3.6</span> Add at the end of the
<code>layout_stride::mapping</code> definition in
[mdspan.layout.stride.overview] after the <code>private:</code> access
specificer:<span></span></a></li>
<li><a href="#add-subsection-24.7.3.7-mdspan.submdspan-with-the-following"><span class="toc-section-number">3.7</span> Add subsection 24.7.3.7
[mdspan.submdspan] with the following<span></span></a></li>
</ul></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>
<h2 data-number="1.1" id="revision-4"><span class="header-section-number">1.1</span> Revision 4:<a href="#revision-4" class="self-link"></a></h2>
<ul>
<li>Implement feedback from LWG</li>
<li>Make <code>submdspan_mapping</code> a hidden friend</li>
<li>Add wording to library introduction that
<code>submdspan_mapping</code> is called via ADL</li>
<li>Make hidden friend call exposition-only implementation detail
functions</li>
<li>Removed is-strided-slice and replace with <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code></li>
<li>Add <code>[[no_unique_address]]</code> and default initialization to
<code>strided_slice</code> and <code>submdspan_mapping_result</code>
members</li>
<li>Make <code>k</code> a template parameter for both
<code>first_</code> and <code>last_</code></li>
<li>Add stuff LWG asked for</li>
</ul>
<h2 data-number="1.2" id="revision-3-mailing-2023-03"><span class="header-section-number">1.2</span> Revision 3: Mailing 2023-03<a href="#revision-3-mailing-2023-03" class="self-link"></a></h2>
<ul>
<li>Add feature test macro</li>
<li>fix wording for aggregate type</li>
<li>make sure sub_map_offset is defined before it is used</li>
<li>use exposition only <em><code>integral-constant-like</code></em>
concept instead of <code>integral_constant</code></li>
</ul>
<h2 data-number="1.3" id="revision-2-mailing-2023-01"><span class="header-section-number">1.3</span> Revision 2: Mailing 2023-01<a href="#revision-2-mailing-2023-01" class="self-link"></a></h2>
<ul>
<li>Add discussion choice of customization point mechanism</li>
<li>rename <code>strided_index_range</code> to
<code>strided_slice</code></li>
<li>introduced named struct combining mapping and offset as return type
for <code>submdspan_mapping</code></li>
<li>removed redundant constraints, which are covered by mandates, thus
users will get a better error message.</li>
<li>fixed layout policy type preservation logic - specifically preserve
layouts for rank zero mappings, and create layout stride if any of the
slice specifiers are <code>stride_index_range</code></li>
<li>fixed submapping extent calculation for <code>strided_slice</code>
where the <code>extent</code> is smaller than the <code>stride</code>
(still should give a submapping extent of 1)</li>
<li>fixed submapping stride calculation for <code>strided_slice</code>
slice specifiers.</li>
<li>added precondition to deal with stride 0
<code>strided_slice</code></li>
</ul>
<h2 data-number="1.4" id="revision-1-mailing-2022-10"><span class="header-section-number">1.4</span> Revision 1: Mailing 2022-10<a href="#revision-1-mailing-2022-10" class="self-link"></a></h2>
<ul>
<li>updated rational for introducing <code>strided_slice</code></li>
<li>merged <code>submdspan_mapping</code> and
<code>submdspan_offset</code> into a single customization point
<code>submdspan_mapping</code> returing a <code>pair</code> of the new
mapping and the offset.</li>
<li>update wording for argument dependent lookup.</li>
</ul>
<h2 data-number="1.5" id="initial-version-2022-08-mailing"><span class="header-section-number">1.5</span> Initial Version 2022-08
Mailing<a href="#initial-version-2022-08-mailing" class="self-link"></a></h2>
<h1 data-number="2" id="description"><span class="header-section-number">2</span> Description<a href="#description" class="self-link"></a></h1>
<p>Until one of the last revisions, the <code>mdspan</code> paper P0009
contained <code>submdspan</code>, the subspan or “slicing” function that
returns a view of a subset of an existing <code>mdspan</code>. This
function was considered critical for the overall functionality of
<code>mdspan</code>. However, due to review time constraints it was
removed from P0009 in order for <code>mdspan</code> to be included in
C++23.</p>
<p>This paper restores <code>submdspan</code>. It also expands on the
original proposal by</p>
<ul>
<li>defining customization points so that <code>submdspan</code> can
work with user-defined layout policies, and</li>
<li>adding the ability to specify slices as compile-time values.</li>
</ul>
<p>Creating subspans is an integral capability of many, if not all
programming languages with multidimensional arrays. These include
Fortran, Matlab, Python, and Python’s NumPy extension.</p>
<p>Subspans are important because they enable code reuse. For example,
the inner loop in a dense matrix-vector product actually represents a
<em>dot product</em> – an inner product of two vectors. If one already
has a function for such an inner product, then a natural implementation
would simply reuse that function. The LAPACK linear algebra library
depends on subspan reuse for the performance of its one-sided “blocked”
matrix factorizations (Cholesky, LU, and QR). These factorizations reuse
textbook non-blocked algorithms by calling them on groups of contiguous
columns at a time. This lets LAPACK spend as much time in dense
matrix-matrix multiply (or algorithms with analogous performance) as
possible.</p>
<p>The following example demonstrates this code reuse feature of
subspans. Given a rank-3 <code>mdspan</code> representing a
three-dimensional grid of regularly spaced points in a rectangular
prism, the function <code>zero_surface</code> sets all elements on the
surface of the 3-dimensional shape to zero. It does so by reusing a
function <code>zero_2d</code> that takes a rank-2
<code>mdspan</code>.</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="co">// Set all elements of a rank-2 mdspan to zero.</span></span>
<span id="cb1-2"><a href="#cb1-2" 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> E, <span class="kw">class</span> L, <span class="kw">class</span> A<span class="op">&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> zero_2d<span class="op">(</span>mdspan<span class="op">&lt;</span>T,E,L,A<span class="op">&gt;</span> grid2d<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>grid2d<span class="op">.</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span><span class="op">)</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><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> grid2d<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<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="cf">for</span><span class="op">(</span><span class="dt">int</span> j <span class="op">=</span> <span class="dv">0</span>; j <span class="op">&lt;</span> grid2d<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>      grid2d<span class="op">[</span>i,j<span class="op">]</span> <span class="op">=</span> <span class="dv">0</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>  <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>
<span id="cb1-12"><a href="#cb1-12" 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> E, <span class="kw">class</span> L, <span class="kw">class</span> A<span class="op">&gt;</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> zero_surface<span class="op">(</span>mdspan<span class="op">&lt;</span>T,E,L,A<span class="op">&gt;</span> grid3d<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>grid3d<span class="op">.</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, <span class="dv">0</span>, full_extent, full_extent<span class="op">))</span>;</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, full_extent, <span class="dv">0</span>, full_extent<span class="op">))</span>;</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, full_extent, full_extent, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, grid3d<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)-</span><span class="dv">1</span>, full_extent, full_extent<span class="op">))</span>;</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, full_extent, grid3d<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)-</span><span class="dv">1</span>, full_extent<span class="op">))</span>;</span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, full_extent, full_extent, grid3d<span class="op">.</span>extent<span class="op">(</span><span class="dv">2</span><span class="op">)-</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="2.1" id="design-of-submdspan"><span class="header-section-number">2.1</span> Design of
<code>submdspan</code><a href="#design-of-submdspan" class="self-link"></a></h2>
<p>As previously proposed in an earlier revision of P0009,
<code>submdspan</code> is a free function. Its first parameter is an
<code>mdspan</code> <code>x</code>, and the remaining
<code>x.rank()</code> parameters are slice specifiers, one for each
dimension of <code>x</code>. The slice specifiers describe which
elements of the range <span class="math inline">[0,</span><code>x.extent(d)</code><span class="math inline">)</span> are part of the multidimensional index
space of the returned <code>mdspan</code>.</p>
<p>This leads to the following fundamental signature:</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">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span> E, <span class="kw">class</span> L, <span class="kw">class</span> A,</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> <span class="op">...</span> SliceArgs<span class="op">)</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> submdspan<span class="op">(</span>mdspan<span class="op">&lt;</span>T,E,L,A<span class="op">&gt;</span> x, SliceArgs <span class="op">...</span> args<span class="op">)</span>;</span></code></pre></div>
<p>where <code>E.rank()</code> must be equal to
<code>sizeof...(SliceArgs)</code>.</p>
<h3 data-number="2.1.1" id="slice-specifiers"><span class="header-section-number">2.1.1</span> Slice Specifiers<a href="#slice-specifiers" class="self-link"></a></h3>
<h4 data-number="2.1.1.1" id="p0009s-slice-specifiers"><span class="header-section-number">2.1.1.1</span> P0009’s slice specifiers<a href="#p0009s-slice-specifiers" class="self-link"></a></h4>
<p>In P0009 we originally proposed three kinds of slice specifiers.</p>
<ul>
<li>A single integral value. For each integral slice specifier given to
<code>submdspan</code>, the rank of the resulting <code>mdspan</code> is
one less than the rank of the input <code>mdspan</code>. The resulting
multidimensional index space contains only elements of the original
index space, where the particular index matches this slice
specifier.</li>
<li>Anything convertible to a
<code>tuple&lt;mdspan::index_type, mdspan::index_type&gt;</code>. The
resulting multidimensional index space covers the begin-to-end subrange
of elements in the original index space described by the
<code>tuple</code>’s two values.</li>
<li>An instance of the tag class <code>full_extent_t</code>. This
includes the full range of indices in that extent in the returned
subspan.</li>
</ul>
<h4 data-number="2.1.1.2" id="strided-index-range-slice-specifier"><span class="header-section-number">2.1.1.2</span> Strided index range slice
specifier<a href="#strided-index-range-slice-specifier" class="self-link"></a></h4>
<p>In other languages which provide multi dimensional arrays with
slicing, often a third type of slice specifier exists. This slicing
modes takes generally a step or stride parameter in addition to a begin
and end value.</p>
<p>For example obtaining a sub-slice starting at the 5th element and
taking every 3rd element up to the 12 can be achieved as:</p>
<ul>
<li>Matlab: <code>A(start:step:end)</code></li>
<li>numpy: <code>A[start:end:step]</code></li>
<li>Fortran: <code>A[start:end:step]</code></li>
</ul>
<p>However, we propose a slightly different design. Instead of providing
begin, end and a step size, we propose to specify begin, extent and a
step size.</p>
<p>This approach has one fundamental advantage: one can combine a
runtime start value with a compile time extent, and thus directly
generate a static extent for the sub-mdspan.</p>
<p>We propose an aggregate type <code>strided_slice</code> to express
this slice specification.</p>
<p>We use a struct with named fields instead of a <code>tuple</code>, in
order to avoid confusion with the order of the three values.</p>
<h5 data-number="2.1.1.2.1" id="extent-vs-step-choice"><span class="header-section-number">2.1.1.2.1</span> <code>extent</code> vs
<code>step</code> choice<a href="#extent-vs-step-choice" class="self-link"></a></h5>
<p>As stated above, we propose specifiying the extent because it makes
taking a submdspan with static extent at a runtime offset easier.</p>
<p>One situation where this is would be used is in certain linear
algebra algorithms, where one steps through a matrix and obtains
submatrices of a specified, compile time known, size.</p>
<p>However, remember the layout and accessor types of a sub mdspan,
depend on the input <code>mdspan</code> and the slice specifiers. Thus
for a generic <code>mdspan</code>, even if one knows the
<code>extents</code> of the resulting <code>mdspan</code> the actual
type is somewhat cumbersome to determine.</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="co">// With start:end:step syntax</span></span>
<span id="cb3-2"><a href="#cb3-2" 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> E, <span class="kw">class</span> L, <span class="kw">class</span> A<span class="op">&gt;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span>mdspan<span class="op">&lt;</span>T,E,L,A<span class="op">&gt;</span> A<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> slice_spec_t <span class="op">=</span> pair<span class="op">&lt;</span><span class="dt">int</span>,<span class="dt">int</span><span class="op">&gt;</span>;</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> subm_t <span class="op">=</span> </span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">decltype</span><span class="op">(</span>submdspan<span class="op">(</span>declval<span class="op">&lt;</span>slcie_spec_t<span class="op">&gt;()</span>, declval<span class="op">&lt;</span>slice_spec_t<span class="op">&gt;()))</span>;</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> static_subm_t <span class="op">=</span> mdspan<span class="op">&lt;</span>T, extents<span class="op">&lt;</span><span class="kw">typename</span> subm_t<span class="op">::</span>index_type, <span class="dv">4</span>, <span class="dv">4</span><span class="op">&gt;</span>,</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>                               <span class="kw">typename</span> subm_t<span class="op">::</span>layout_type,</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>                               <span class="kw">typename</span> subm_t<span class="op">::</span>accessor_type<span class="op">&gt;</span>;</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i<span class="op">=</span><span class="dv">0</span>; i<span class="op">&lt;</span>A<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; i<span class="op">)</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> j<span class="op">=</span><span class="dv">0</span>; j<span class="op">&lt;</span>A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; j<span class="op">++)</span> <span class="op">{</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>      static_subm_t subm <span class="op">=</span> submdspan<span class="op">(</span>A, slice_spec_t<span class="op">(</span>i,i<span class="op">+</span><span class="dv">4</span><span class="op">)</span>, slice_spec_t<span class="op">(</span>j,j<span class="op">+</span><span class="dv">4</span><span class="op">))</span>;</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>      <span class="co">// ...</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a><span class="co">// With the proposed type:</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-20"><a href="#cb3-20" 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> E, <span class="kw">class</span> L, <span class="kw">class</span> A<span class="op">&gt;</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span>mdspan<span class="op">&lt;</span>T,E,L,A<span class="op">&gt;</span> A<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> slice_spec_t <span class="op">=</span> </span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a>    strided_slice<span class="op">&lt;</span><span class="dt">int</span>, integral_constant<span class="op">&lt;</span><span class="dt">int</span>,<span class="dv">4</span><span class="op">&gt;</span>, integral_constant<span class="op">&lt;</span><span class="dt">int</span>,<span class="dv">1</span><span class="op">&gt;&gt;</span>;</span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i<span class="op">=</span><span class="dv">0</span>; i<span class="op">&lt;</span>A<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; i<span class="op">)</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> j<span class="op">=</span><span class="dv">0</span>; j<span class="op">&lt;</span>A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; j<span class="op">++)</span> <span class="op">{</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a>      <span class="kw">auto</span> subm <span class="op">=</span> submdspan<span class="op">(</span>A, slice_spec_t<span class="op">{</span>i<span class="op">}</span>, slice_spec_t<span class="op">{</span>j<span class="op">})</span>;</span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a>      <span class="co">// ...</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Furthermore, even if one accepts the more complex specification of
<code>subm</code> it likely that the first variant would require more
instructions, since compile time information about extents is not
available during the <code>submdspan</code> call.</p>
<h5 data-number="2.1.1.2.2" id="template-argument-deduction"><span class="header-section-number">2.1.1.2.2</span> Template argument
deduction<a href="#template-argument-deduction" class="self-link"></a></h5>
<p>We really want template argument deduction to work for
<code>strided_slice</code>. Languages like Fortran, Matlab, and Python
have a concise notation for creating the equivalent kind of slice
inline. It would be unfortunate if users had to write</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">auto</span> y <span class="op">=</span> submdspan<span class="op">(</span>x, strided_slice<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">int</span>, <span class="dt">int</span><span class="op">&gt;{</span><span class="dv">0</span>, <span class="dv">10</span>, <span class="dv">3</span><span class="op">})</span>;</span></code></pre></div>
<p>instead of</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> y <span class="op">=</span> submdspan<span class="op">(</span>x, strided_slice<span class="op">{</span><span class="dv">0</span>, <span class="dv">10</span>, <span class="dv">3</span><span class="op">})</span>;</span></code></pre></div>
<p>Not having template argument deduction would make it particularly
unpleasant to mix compile-time and run-time values. For example, to
express the offset and extent as compile-time values and the stride as a
run-time value without template argument deduction, users would need to
write</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><span class="kw">auto</span> y <span class="op">=</span> submdspan<span class="op">(</span>x, strided_slice<span class="op">&lt;</span>integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">0</span><span class="op">&gt;</span>, integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">10</span><span class="op">&gt;</span>, <span class="dv">3</span><span class="op">&gt;{{}</span>, <span class="op">{}</span>, <span class="dv">3</span><span class="op">})</span>;</span></code></pre></div>
<p>Template argument deduction would permit a consistently
value-oriented style.</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><span class="kw">auto</span> y <span class="op">=</span> submdspan<span class="op">(</span>x, strided_slice<span class="op">{</span>integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">0</span><span class="op">&gt;{}</span>, integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">10</span><span class="op">&gt;{}</span>, <span class="dv">3</span><span class="op">})</span>;</span></code></pre></div>
<p>This case of compile-time offset and extent and run-time stride would
permit optimizations like</p>
<ul>
<li><p>preserving the input mdspan’s accessor type (e.g., for aligned
access) when the offset is zero; and</p></li>
<li><p>ensuring that the <code>submdspan</code> result has a static
extent.</p></li>
</ul>
<h5 data-number="2.1.1.2.3" id="designated-initializers"><span class="header-section-number">2.1.1.2.3</span> Designated initializers<a href="#designated-initializers" class="self-link"></a></h5>
<p>We would <em>also</em> like to permit use of designated initializers
with <code>strided_slice</code>. This would let users choose a more
verbose, self-documenting style. It would also avoid any confusion about
the order of arguments.</p>
<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">auto</span> y <span class="op">=</span> submdspan<span class="op">(</span>x, strided_slice<span class="op">{.</span>offset<span class="op">=</span><span class="dv">0</span>, <span class="op">.</span>extent<span class="op">=</span><span class="dv">10</span>, <span class="op">.</span>stride<span class="op">=</span><span class="dv">3</span><span class="op">})</span>;</span></code></pre></div>
<p>Designated initializers only work for aggregate types. This has
implications for template argument deduction. Template argument
deduction for aggregates is a C++20 feature. However, few compilers
support it currently. GCC added full support in version 11, MSVC in
19.27, and EDG eccp in 6.3, according to the <a href="https://en.cppreference.com/w/cpp/compiler_support">cppreference.com
compiler support table</a>. For example, Clang 14.0.0 supports
designated initializers, and <em>non</em>-aggregate (class) template
argument deduction, but it does not currently compile either of the
following.</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="kw">auto</span> a <span class="op">=</span> strided_slice<span class="op">{.</span>offset<span class="op">=</span><span class="dv">0</span>, <span class="op">.</span>extent<span class="op">=</span><span class="dv">10</span>, <span class="op">.</span>stride<span class="op">=</span><span class="dv">3</span><span class="op">}</span>;</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> b <span class="op">=</span> strided_slice<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">int</span>, <span class="dt">int</span><span class="op">&gt;{.</span>offset<span class="op">=</span><span class="dv">0</span>, <span class="op">.</span>extent<span class="op">=</span><span class="dv">10</span>, <span class="op">.</span>stride<span class="op">=</span><span class="dv">3</span><span class="op">})</span>;</span></code></pre></div>
<p>Implementers may want to make mdspan available for users of earlier
C++ versions. The result need not comply fully with the specification,
but should be as usable and forward-compatible as possible. Implementers
can back-port <code>strided_slice</code> by adding the following two
constructors.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>strided_slice<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>strided_slice<span class="op">(</span>OffsetType offset_, ExtentType extent_, StrideType stride_<span class="op">)</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">:</span> offset<span class="op">(</span>offset_<span class="op">)</span>, extent_<span class="op">(</span>extent<span class="op">)</span>, stride<span class="op">(</span>stride_<span class="op">)</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">{}</span></span></code></pre></div>
<p>These constructors make <code>strided_slice</code> no longer an
aggregate, but restore (class) template argument deduction. They also
preserve the struct’s properties of being a structural type (usable as a
non-type template parameter) and trivially copyable (for compatibility
with other programming languages).</p>
<h4 data-number="2.1.1.3" id="compile-time-integral-values-in-slices"><span class="header-section-number">2.1.1.3</span> Compile-time integral
values in slices<a href="#compile-time-integral-values-in-slices" class="self-link"></a></h4>
<p>We also propose that any integral value (on its own, in a
<code>tuple</code>, or in <code>strided_slice</code>) can be specified
as an <code>integral_constant</code>. This ensures that the value can be
baked into the return <em>type</em> of <code>submdspan</code>. For
example, layout mappings could be entirely compile time.</p>
<p>Here are some simple examples for rank-1 <code>mdspan</code>.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span><span class="op">*</span> ptr <span class="op">=</span> <span class="op">...</span>;</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> N <span class="op">=</span> <span class="op">...</span>;</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>mdspan a<span class="op">(</span>ptr, N<span class="op">)</span>;</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="co">// subspan of a single element</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> a_sub1 <span class="op">=</span> submdspan<span class="op">(</span>a, <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span><span class="kw">decltype</span><span class="op">(</span>a_sub1<span class="op">)::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(&amp;</span>a_sub1<span class="op">()</span> <span class="op">==</span> <span class="op">&amp;</span>a<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a><span class="co">// subrange</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> a_sub2 <span class="op">=</span> submdspan<span class="op">(</span>a, tuple<span class="op">{</span><span class="dv">1</span>, <span class="dv">4</span><span class="op">})</span>;</span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span><span class="kw">decltype</span><span class="op">(</span>a_sub2<span class="op">)::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(&amp;</span>a_sub2<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> <span class="op">&amp;</span>a<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>a_sub2<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> <span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a><span class="co">// subrange with stride</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> a_sub3 <span class="op">=</span> submdspan<span class="op">(</span>a, strided_slice<span class="op">{</span><span class="dv">1</span>, <span class="dv">7</span>, <span class="dv">2</span><span class="op">})</span>;</span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span><span class="kw">decltype</span><span class="op">(</span>a_sub3<span class="op">)::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(&amp;</span>a_sub3<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> <span class="op">&amp;</span>a<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(&amp;</span>a_sub3<span class="op">(</span><span class="dv">3</span><span class="op">)</span> <span class="op">==</span> <span class="op">&amp;</span>a<span class="op">(</span><span class="dv">7</span><span class="op">))</span>;</span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>a_sub3<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> <span class="dv">4</span><span class="op">)</span>;</span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a><span class="co">// full range</span></span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> a_sub4 <span class="op">=</span> submdspan<span class="op">(</span>a, full_extent<span class="op">)</span>;</span>
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span><span class="kw">decltype</span><span class="op">(</span>a_sub4<span class="op">)::</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>a_sub4<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> a<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>a_sub4<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span></code></pre></div>
<p>In multidimensional use cases these specifiers can be mixed and
matched.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span><span class="op">*</span> ptr <span class="op">=</span> <span class="op">...</span>;</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> N0 <span class="op">=</span> <span class="op">...</span>, N1 <span class="op">=</span> <span class="op">...</span>, N2 <span class="op">=</span> <span class="op">...</span>, N3 <span class="op">=</span> <span class="op">...</span>, N4 <span class="op">=</span> <span class="op">...</span>;</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>mdspan a<span class="op">(</span>ptr, N0, N1, N2, N3, N4<span class="op">)</span>;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> a_sub <span class="op">=</span> submdspan<span class="op">(</span>a,full_extent_t<span class="op">()</span>, <span class="dv">3</span>, strided_slice<span class="op">{</span><span class="dv">2</span>,N2<span class="op">-</span><span class="dv">5</span>, <span class="dv">2</span><span class="op">}</span>, <span class="dv">4</span>, tuple<span class="op">{</span><span class="dv">3</span>, N5<span class="op">-</span><span class="dv">5</span><span class="op">})</span>;</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a><span class="co">// two integral specifiers so the rank is reduced by 2</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span><span class="kw">decltype</span><span class="op">(</span>a_sub<span class="op">)</span> <span class="op">==</span> <span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="co">// 1st dimension is taking the whole extent</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>a_sub<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="co">// the new 2nd dimension corresponds to the old 3rd dimension</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>a_sub<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">==</span> <span class="op">(</span>a<span class="op">.</span>extent<span class="op">(</span><span class="dv">2</span><span class="op">)</span> <span class="op">-</span> <span class="dv">5</span><span class="op">)/</span><span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>a_sub<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span> <span class="op">==</span> a<span class="op">.</span>stride<span class="op">(</span><span class="dv">2</span><span class="op">)*</span><span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a><span class="co">// the new 3rd dimension corresponds to the old 5th dimension</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>a_sub<span class="op">.</span>extent<span class="op">(</span><span class="dv">2</span><span class="op">)</span> <span class="op">==</span> a<span class="op">.</span>extent<span class="op">(</span><span class="dv">4</span><span class="op">)-</span><span class="dv">8</span><span class="op">)</span>;</span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(&amp;</span>a_sub<span class="op">(</span><span class="dv">1</span>,<span class="dv">5</span>,<span class="dv">7</span><span class="op">)</span> <span class="op">==</span> <span class="op">&amp;</span>a<span class="op">(</span><span class="dv">1</span>, <span class="dv">3</span>, <span class="dv">2</span><span class="op">+</span><span class="dv">5</span><span class="op">*</span><span class="dv">2</span>, <span class="dv">4</span>, <span class="dv">3</span><span class="op">+</span><span class="dv">7</span><span class="op">))</span>;</span></code></pre></div>
<h3 data-number="2.1.2" id="customization-points"><span class="header-section-number">2.1.2</span> Customization Points<a href="#customization-points" class="self-link"></a></h3>
<p>In order to create the new <code>mdspan</code> from an existing
<code>mdspan</code> <code>src</code>, we need three things:</p>
<ul>
<li><p>the new mapping <code>sub_map</code>,</p></li>
<li><p>the new accessor <code>sub_acc</code>, and</p></li>
<li><p>the new data handle <code>sub_handle</code>.</p></li>
</ul>
<p>Computing the new data handle is done via an <em>offset</em> and the
original accessor’s <code>offset</code> function, while the new accessor
is constructed from the old accessor.</p>
<p>That leaves the construction of the new mapping and the calculation
of the <em>offset</em> handed to the <code>offset</code> function. Both
of those operations depend only on the old mapping and the slice
specifiers.</p>
<p>In order to support calling <code>submdspan</code> on
<code>mdspan</code> with custom layout policies, we need to introduce
two customization points for computing the mapping and the offset. Both
take as input the original mapping, and the slice specifiers.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Mapping, <span class="kw">class</span> <span class="op">...</span> SliceArgs<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> submdspan_mapping<span class="op">(</span><span class="kw">const</span> Mapping<span class="op">&amp;</span>, SliceArgs<span class="op">...)</span> <span class="op">{</span> <span class="co">/* ... */</span> <span class="op">}</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Mapping, <span class="kw">class</span> <span class="op">...</span> SliceArgs<span class="op">&gt;</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="dt">size_t</span> submdspan_offset<span class="op">(</span><span class="kw">const</span> Mapping<span class="op">&amp;</span>, SliceArgs<span class="op">...)</span> <span class="op">{</span> <span class="co">/* ... */</span> <span class="op">}</span></span></code></pre></div>
<p>Since both of these function may require computing similar
information, one should actually fold <code>submdspan_offset</code> into
<code>submdspan_mapping</code> and make that single customization point
return a struct containing both the submapping and offset.</p>
<p>With these components we can sketch out the implementation of
<code>submdspan</code>.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span> E, <span class="kw">class</span> L, <span class="kw">class</span> A,</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> <span class="op">...</span> SliceArgs<span class="op">)</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> submdspan<span class="op">(</span><span class="kw">const</span> mdspan<span class="op">&lt;</span>T,E,L,A<span class="op">&gt;&amp;</span> src, SliceArgs <span class="op">...</span> args<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-4"><a href="#cb14-4" 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>, args<span class="op">...)</span>;</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> A<span class="op">::</span>offset_policy sub_acc<span class="op">(</span>src<span class="op">.</span>accessor<span class="op">())</span>;</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> A<span class="op">::</span>offset_policy<span class="op">::</span>data_handle_type </span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    sub_handle <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_handle<span class="op">()</span>, sub_offset<span class="op">)</span>;</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> mdspan<span class="op">(</span>sub_handle, sub_map_offset<span class="op">.</span>first, sub_map_offset<span class="op">.</span>second<span class="op">)</span>;</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>To support custom layouts, <code>std::submdspan</code> calls
<code>submdspan_mapping</code> using argument-dependent lookup.</p>
<p>However, not all layout mappings may support efficient slicing for
all possible slice specifier combinations. Thus, we do <em>not</em>
propose to add this customization point to the layout policy
requirements.</p>
<h3 data-number="2.1.3" id="pure-adl-vs.-cpo-vs.-tag-invoke"><span class="header-section-number">2.1.3</span> Pure ADL vs. CPO vs. tag
invoke<a href="#pure-adl-vs.-cpo-vs.-tag-invoke" class="self-link"></a></h3>
<p>In this paper we propose to implement the customization point via
pure ADL (argument-dependent lookup), that is, by calling functions with
particular reserved names unqualified. To evaluate whether there would
be significant benefits of using customization point objects (CPOs) or a
<code>tag_invoke</code> approach, we followed the discussion presented
in P2279.</p>
<p>But first we need to discuss the expected use case scenario. Most
users will never call this customization point directly. Instead it is
invoked via <code>std::submdspan</code>, which returns an mdspan viewing
the subset of elements indicated by the caller’s slice specifiers. The
only place where users of C++ would call <code>submdspan_mapping</code>
directly is when writing functions that behave analogously to
<code>std::submdspan</code> for other data structures. For example a
user may want to have a shared ownership variant of <code>mdspan</code>.
However, in most cases where we have seen higher level data structures
with multi-dimensional indexing, that higher level data structure
actually contains an entire <code>mdspan</code> (or its predecessor
<code>Kokkos::View</code> from the Kokkos library). Getting subsets of
the data then delegates to calling <code>submdspan</code> instead of
directly working on the underlying mapping.</p>
<p>The only implementers of <code>submdspan_mapping</code> are
developers of a custom layout policy for <code>mdspan</code>. We expect
the number of such developers to be multiple orders of magnitude smaller
than actual users of <code>mdspan</code>.</p>
<p>One important consideration for <code>submdspan_mapping</code> is
that there is no default implementation. That is, this customization
point is not used to override some default behavior, unlike functions
such as <code>std::swap</code> that have a default behavior that users
might like to override for their types.</p>
<p>In P2279 Pure ADL, CPOs and <code>tag_invoke</code> were evaluated on
9 criteria. Here we will focus on the criteria where ADL, CPOs and
<code>tag_invoke</code> got different “marks.”</p>
<h4 data-number="2.1.3.1" id="explicit-opt-in"><span class="header-section-number">2.1.3.1</span> Explicit Opt In<a href="#explicit-opt-in" class="self-link"></a></h4>
<p>One drawback for pure ADL is that it is not blazingly obvious that a
function is an implementation of a customization point. Whether some
random user function <code>begin</code> or <code>swap</code> is actually
something intended to work with <code>ranges::begin</code> or
<code>std::swap</code>, is impossible to judge at first sight.
<code>tag_invoke</code> improves on that situation by making it
blazingly obvious since the actual functions one implements is called
<code>tag_invoke</code> which takes a <code>std::tag</code>. However, in
our case the name of the overloaded function is extremely specific:
<code>submdspan_mapping</code>. We do not believe that many people will
be confused whether such a function, taking a layout policy mapping and
slice specifiers as arguments, is intended as an implementation point
for the customization point of <code>submdspan</code> or not.</p>
<h4 data-number="2.1.3.2" id="diagnose-incorrect-opt-in"><span class="header-section-number">2.1.3.2</span> Diagnose Incorrect Opt In<a href="#diagnose-incorrect-opt-in" class="self-link"></a></h4>
<p>CPOs and <code>tag_invoke</code> got a “shrug” in P2279, because they
may or may not be a bit better checkable than pure ADL. However, in the
primary use of <code>submdspan_mapping</code> via call in
<code>submdspan</code> we can largely check whether the function does
what we expect. Specifically, the return type has to meet a set of well
defined criteria - it needs to be a layout mapping, with
<code>extents</code> which are defined by
<code>std::submdspan_extents</code>. In fact <code>submdspan</code>
mandates some of that static information matching the expectations.</p>
<h4 data-number="2.1.3.3" id="associated-types"><span class="header-section-number">2.1.3.3</span> Associated Types<a href="#associated-types" class="self-link"></a></h4>
<p>In the case of <code>submdspan_mapping</code> there are no associated
types per se (in the way we understood that criterion). For a function
like</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>T<span class="op">::</span>iterator begin<span class="op">(</span>T<span class="op">)</span>;</span></code></pre></div>
<p><code>T</code> itself knows the return type. However for
<code>submdspan_mapping</code> the return type depends not just on the
source mapping, but also all the slice specifier types. Thus the only
way to get it is effectively asking the return type of the function,
however that function is implemented. In fact I would argue that:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">decltype</span><span class="op">(</span>submdspan_mapping<span class="op">(</span>declval<span class="op">(</span>mapping_t<span class="op">)</span>, <span class="dt">int</span>, <span class="dt">int</span>, full_extent_t, <span class="dt">int</span><span class="op">))</span>;</span></code></pre></div>
<p>is more concise than a possible <code>tag_invoke</code> scheme
here.</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">decltype</span><span class="op">(</span>std<span class="op">::</span>tag_invoke<span class="op">(</span>std<span class="op">::</span>tag<span class="op">&lt;</span>std<span class="op">::</span>submdspan_mapping<span class="op">&gt;</span>,declval<span class="op">(</span>mapping_t, <span class="dt">int</span>, <span class="dt">int</span>, full_extent_t, <span class="dt">int</span><span class="op">)))</span>;</span></code></pre></div>
<h4 data-number="2.1.3.4" id="easily-invoke-the-customization"><span class="header-section-number">2.1.3.4</span> Easily invoke the
customization<a href="#easily-invoke-the-customization" class="self-link"></a></h4>
<p>This is likely the biggest drawback of the ADL approach. If one
indeed just needs the sub-mapping in a generic context, one has to
remember to use ADL. However, there are two mitigating facts:</p>
<ul>
<li><p>it will be very rare that someone needs to call the
<code>submdspan_mapping</code> directly - at least compared to calling
<code>submdspan</code></p></li>
<li><p>the failure mode of calling <code>std::submdspan</code> on a
custom mapping type, is an error at compile time - not calling a
potential faulty default implementation.</p></li>
</ul>
<h4 data-number="2.1.3.5" id="conclusion"><span class="header-section-number">2.1.3.5</span> Conclusion<a href="#conclusion" class="self-link"></a></h4>
<p>All in all this evaluation let us to believe that there are no
significant benefits in prefering CPOs or <code>tag_invoke</code> over
pure ADL for <code>submdspan_mapping</code>. However, considering the
expected rareness of someone implementing the customization point, this
is not something we consider a large issue. If the committee disagrees
with our evaluation we are happy to use <code>tag_invoke</code> instead
- which we believe is preferable over a CPO approach.</p>
<h3 data-number="2.1.4" id="making-sure-submdspan-behavior-meets-expectations"><span class="header-section-number">2.1.4</span> Making sure submdspan
behavior meets expectations<a href="#making-sure-submdspan-behavior-meets-expectations" class="self-link"></a></h3>
<p>The slice specifiers of <code>submdspan</code> completely determine
two properties of its result:</p>
<ol type="1">
<li>the <code>extents</code> of the result, and</li>
<li>what elements of the input of <code>submdspan</code> are also
represented in the result.</li>
</ol>
<p>Both of these things are independent of the layout mapping
policy.</p>
<p>The approach we described above orthogonalizes handling of accessors
and mappings. Thus, we can define both of the above properties via the
multidimensional index spaces, regardless of what it means to “refer to
the same element.” (For example, accessors may use proxy references and
data handle types other than C++ pointers. This makes it hard to define
what “same element” means.) That will let us define pre-conditions for
<code>submdspan</code> which specify the required behavior of any
user-provided <code>submdspan_mapping</code> function.</p>
<p>One function which can help with that, and additionally is needed to
implement <code>submdspan_mapping</code> for the layouts the standard
provides, is a function to compute the submdspan’s <code>extents</code>.
We will propose this function as a public function in the standard:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> IndexType, <span class="kw">class</span> <span class="op">...</span> Extents, <span class="kw">class</span> <span class="op">...</span> SliceArgs<span class="op">&gt;</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> submdspan_extents<span class="op">(</span><span class="kw">const</span> extents<span class="op">&lt;</span>IndexType, Extents<span class="op">...&gt;</span>, SliceArgs <span class="op">...)</span>;</span></code></pre></div>
<p>The resulting <code>extents</code> object must have certain
properties for logical correctness.</p>
<ul>
<li><p>The rank of the sub-extents is the rank of the original
<code>extents</code> minus the number of pure integral arguments in
<code>SliceArgs</code>.</p></li>
<li><p>The extent of each remaining dimension is well defined by the
<code>SliceArgs</code>. It is the original extent if all the
<code>SliceArgs</code> are <code>full_extent_t</code>.</p></li>
</ul>
<p>For performance and preservation of compile-time knowledge, we also
require the following.</p>
<ul>
<li><p>Any <code>full_extent_t</code> argument corresponding to a static
extent, preserves that static extent.</p></li>
<li><p>Generate a static extent when possible. For example, providing a
<code>tuple</code> of <code>integral_constant</code> as a slice
specifier ensures that the corresponding extent is static.</p></li>
</ul>
<h1 data-number="3" id="wording"><span class="header-section-number">3</span> Wording<a href="#wording" class="self-link"></a></h1>
<blockquote>
<p><em>In <b>[version.syn]</b>, add:</em></p>
</blockquote>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#define __cpp_lib_submdspan </span>YYYYMML<span class="pp"> </span><span class="co">// also in &lt;mdspan&gt;</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Adjust the placeholder value as needed so as to denote this proposal’s
date of adoption.</p>
<h2 data-number="3.1" id="modify-first-sentence-in-paragraph-3-of-contents-16.4.2.2-to-be"><span class="header-section-number">3.1</span> Modify first sentence in
paragraph 3 of [contents] (16.4.2.2) to be:<a href="#modify-first-sentence-in-paragraph-3-of-contents-16.4.2.2-to-be" class="self-link"></a></h2>
<p>Whenever an unqualified name other than <code class="rm">swap</code>,
<code>make_error_code</code>, <span class="rm" style="color: #bf0303"><del>or</del></span>
<code>make_error_condition</code><span class="add" style="color: #00AA00"><ins>, or
<span><code>submdspan_mapping</code></span></ins></span> is used in the
specification of a declaration D in [support] through [thread] or
[depr], its meaning is established as-if by performing unqualified name
lookup ([basic.lookup.unqual]) in the context of D.</p>
<h2 data-number="3.2" id="modify-last-sentence-in-paragraph-3-of-contents-16.4.2.2-to-be"><span class="header-section-number">3.2</span> Modify last sentence in
paragraph 3 of [contents] (16.4.2.2) to be:<a href="#modify-last-sentence-in-paragraph-3-of-contents-16.4.2.2-to-be" class="self-link"></a></h2>
<p>The meanings of the unqualified names
<code>make_error_code</code><span class="add" style="color: #00AA00"><ins>,</ins></span> <span class="rm" style="color: #bf0303"><del>and</del></span>
<code>make_error_condition</code><span class="add" style="color: #00AA00"><ins>, and
<span><code>submdspan_mapping</code></span></ins></span> are established
as-if by performing argument-dependent lookup
([basic.lookup.argdep]).</p>
<h2 data-number="3.3" id="add-inside-namespace-std-at-the-end-of-synopsis-in-subsection-24.7.3.2-mdspan.syn"><span class="header-section-number">3.3</span> Add inside namespace std at the
end of synopsis in subsection 24.7.3.2 [mdspan.syn]<a href="#add-inside-namespace-std-at-the-end-of-synopsis-in-subsection-24.7.3.2-mdspan.syn" class="self-link"></a></h2>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.submdspan], submdspan creation</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OffsetType, <span class="kw">class</span> LengthType, <span class="kw">class</span> StrideType<span class="op">&gt;</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> strided_slice;</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutMapping<span class="op">&gt;</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> submdspan_mapping_result;</span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> IndexType, <span class="kw">class</span><span class="op">...</span> Extents, <span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan_extents<span class="op">(</span><span class="kw">const</span> extents<span class="op">&lt;</span>IndexType, Extents<span class="op">...&gt;&amp;</span>,</span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>                                     SliceSpecifiers <span class="op">...)</span>;</span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="kw">class</span> Extents, <span class="kw">class</span> LayoutPolicy,</span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a>           <span class="kw">class</span> AccessorPolicy, <span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan<span class="op">(</span></span>
<span id="cb20-15"><a href="#cb20-15" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mdspan<span class="op">&lt;</span>ElementType, Extents, LayoutPolicy, AccessorPolicy<span class="op">&gt;&amp;</span> src,</span>
<span id="cb20-16"><a href="#cb20-16" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers<span class="op">...</span>slices<span class="op">)</span> <span class="op">-&gt;</span> <em>see below</em>;</span>
<span id="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">concept</span> <em>integral-constant-like</em> <span class="op">=</span>                                     <span class="co">// <em>exposition only</em></span></span>
<span id="cb20-20"><a href="#cb20-20" aria-hidden="true" tabindex="-1"></a>    is_integral_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>T<span class="op">::</span>value<span class="op">)&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-21"><a href="#cb20-21" aria-hidden="true" tabindex="-1"></a>    <span class="op">!</span>is_same_v<span class="op">&lt;</span><span class="dt">bool</span>, remove_const_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>T<span class="op">::</span>value<span class="op">)&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-22"><a href="#cb20-22" aria-hidden="true" tabindex="-1"></a>    convertible_to<span class="op">&lt;</span>T, <span class="kw">decltype</span><span class="op">(</span>T<span class="op">::</span>value<span class="op">)&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-23"><a href="#cb20-23" aria-hidden="true" tabindex="-1"></a>    equality_comparable_with<span class="op">&lt;</span>T, <span class="kw">decltype</span><span class="op">(</span>T<span class="op">::</span>value<span class="op">)&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-24"><a href="#cb20-24" aria-hidden="true" tabindex="-1"></a>    bool_constant<span class="op">&lt;</span>T<span class="op">()</span> <span class="op">==</span> T<span class="op">::</span>value<span class="op">&gt;::</span>value <span class="op">&amp;&amp;</span></span>
<span id="cb20-25"><a href="#cb20-25" aria-hidden="true" tabindex="-1"></a>    bool_constant<span class="op">&lt;</span><span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>T<span class="op">::</span>value<span class="op">)&gt;(</span>T<span class="op">())</span> <span class="op">==</span> T<span class="op">::</span>value<span class="op">&gt;::</span>value;</span>
<span id="cb20-26"><a href="#cb20-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-27"><a href="#cb20-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-28"><a href="#cb20-28" 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="cb20-29"><a href="#cb20-29" aria-hidden="true" tabindex="-1"></a>  <span class="kw">concept</span> <em>index-pair-like</em> <span class="op">=</span>                        <span class="co">// <em>exposition only</em></span></span>
<span id="cb20-30"><a href="#cb20-30" aria-hidden="true" tabindex="-1"></a>    <em>pair-like</em><span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb20-31"><a href="#cb20-31" 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="cb20-32"><a href="#cb20-32" 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>
<h2 data-number="3.4" id="add-at-the-end-of-the-layout_leftmapping-definition-in-mdspan.layout.left.overview-after-the-private-access-specificer"><span class="header-section-number">3.4</span> Add at the end of the
<code>layout_left::mapping</code> definition in
[mdspan.layout.left.overview] after the <code>private:</code> access
specificer:<a href="#add-at-the-end-of-the-layout_leftmapping-definition-in-mdspan.layout.left.overview-after-the-private-access-specificer" class="self-link"></a></h2>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.submdspan.mapping], submdspan mapping specialization</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> <em>submdspan-mapping-impl</em><span class="op">(</span>                  <span class="co">// <em>exposition only</em></span></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan_mapping<span class="op">(</span></span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mapping<span class="op">&amp;</span> src, SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="op">{</span></span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> src<span class="op">.</span><em>submdspan-mapping-impl</em><span class="op">(</span>slices<span class="op">...)</span>;</span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span></code></pre></div>
<h2 data-number="3.5" id="add-at-the-end-of-the-layout_rightmapping-definition-in-mdspan.layout.right.overview-after-the-private-access-specificer"><span class="header-section-number">3.5</span> Add at the end of the
<code>layout_right:mapping</code> definition in
[mdspan.layout.right.overview] after the <code>private:</code> access
specificer:<a href="#add-at-the-end-of-the-layout_rightmapping-definition-in-mdspan.layout.right.overview-after-the-private-access-specificer" class="self-link"></a></h2>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.submdspan.mapping], submdspan mapping specialization</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> <em>submdspan-mapping-impl</em><span class="op">(</span>                 <span class="co">// <em>exposition only</em></span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan_mapping<span class="op">(</span></span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mapping<span class="op">&amp;</span> src, SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> src<span class="op">.</span><em>submdspan-mapping-impl</em><span class="op">(</span>slices<span class="op">...)</span>;</span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span></code></pre></div>
<h2 data-number="3.6" id="add-at-the-end-of-the-layout_stridemapping-definition-in-mdspan.layout.stride.overview-after-the-private-access-specificer"><span class="header-section-number">3.6</span> Add at the end of the
<code>layout_stride::mapping</code> definition in
[mdspan.layout.stride.overview] after the <code>private:</code> access
specificer:<a href="#add-at-the-end-of-the-layout_stridemapping-definition-in-mdspan.layout.stride.overview-after-the-private-access-specificer" class="self-link"></a></h2>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.submdspan.mapping], submdspan mapping specialization</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> <em>submdspan-mapping-impl</em><span class="op">(</span>                 <span class="co">// <em>exposition only</em></span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan_mapping<span class="op">(</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mapping<span class="op">&amp;</span> src, SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> src<span class="op">.</span><em>submdspan-mapping-impl</em><span class="op">(</span>slices<span class="op">...)</span>;</span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span></code></pre></div>
<h2 data-number="3.7" id="add-subsection-24.7.3.7-mdspan.submdspan-with-the-following"><span class="header-section-number">3.7</span> Add subsection 24.7.3.7
[mdspan.submdspan] with the following<a href="#add-subsection-24.7.3.7-mdspan.submdspan-with-the-following" class="self-link"></a></h2>
<p><b>24.7.3.7 submdspan [mdspan.submdspan]</b></p>
<p><b>24.7.3.7.1 overview [mdspan.submdspan.overview]</b></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The <code>submdspan</code> facilities create a new <code>mdspan</code>
viewing a subset of elements of an existing input <code>mdspan</code>.
The subset viewed by the created <code>mdspan</code> is determined by
the <code>SliceSpecifier</code> arguments.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
For each function defined in subsection [mdspan.submdspan] that takes a
parameter pack named <code>slices</code> as an argument:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> let
<code>index_type</code> be</p>
<ul>
<li><p><code>M::index_type</code> if the function is a member of a class
<code>M</code>, otherwise</p></li>
<li><p><code>remove_reference_t&lt;decltype(src)&gt;::index_type</code>
if the function has a parameter named <code>src</code>,
otherwise</p></li>
<li><p>the same type as the function’s template argument
<code>IndexType</code>;</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span> let
<code>rank</code> be the number of elements in
<code>slices</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> let
<span class="math inline"><em>s</em><sub><em>k</em></sub></span> be the
<span class="math inline"><em>k</em></span>-th element of
<code>slices</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span> let
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> be the
type of <span class="math inline"><em>s</em><sub><em>k</em></sub></span>; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.5)</a></span> let
<em><code>map-rank</code></em> be an
<code>array&lt;size_t, rank&gt;</code> such that for each <code>k</code>
in the range of <span class="math inline">[0,</span>
<code>rank</code><span class="math inline">)</span>,
<em><code>map-rank</code></em><code>[k]</code> equals:</p>
<ul>
<li><p><code>dynamic_extent</code> if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<code>convertible_to&lt;index_type&gt;</code>, otherwise</p></li>
<li><p>the number of types <span class="math inline"><em>S</em><sub><em>j</em></sub></span> with <span class="math inline"><em>j</em> &lt; <em>k</em></span> that do not model
<code>convertible_to&lt;index_type&gt;</code>.</p></li>
</ul></li>
</ul>
<p><b>24.7.3.7.2 <code>strided_slice</code>
[mdspan.submdspan.strided_slice]</b></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code>strided_slice</code> represents a set of <code>extent</code>
regularly spaced integer indices. The indices start at
<code>offset</code>, and increase by increments of
<code>stride</code>.</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OffsetType, <span class="kw">class</span> ExtentType, <span class="kw">class</span> StrideType<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> strided_slice <span class="op">{</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> offset_type <span class="op">=</span> OffsetType;</span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> extent_type <span class="op">=</span> ExtentType;</span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> stride_type <span class="op">=</span> StrideType;</span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">[[</span><span class="at">no_unique_address</span><span class="op">]]</span> OffsetType offset<span class="op">{}</span>;</span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">[[</span><span class="at">no_unique_address</span><span class="op">]]</span> ExtentType extent<span class="op">{}</span>;</span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">[[</span><span class="at">no_unique_address</span><span class="op">]]</span> StrideType stride<span class="op">{}</span>;</span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<code>strided_slice</code> has the data members and special members
specified above. It has no base classes or members other than those
specified.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> <code>OffsetType</code>, <code>ExtentType</code>, and
<code>StrideType</code> are signed or unsigned integer types, or model
<em><code>integral-constant-like</code></em>.</p>
<p><i>[Note: </i>
<code>strided_slice{.offset=1, .extent=10, .stride=3}</code> indicates
the indices 1, 4, 7, and 10. Indices are selected from the half-open
interval [1, 1 + 10). <i>- end note]</i></p>
<p><b>24.7.3.7.3 <code>submdspan_mapping_result</code>
[mdspan.submdspan.submdspan_mapping_result]</b></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Specializations of <code>submdspan_mapping_result</code> are returned by
overloads of <code>submdspan_mapping</code>.</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutMapping<span class="op">&gt;</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> submdspan_mapping_result <span class="op">{</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">[[</span><span class="at">no_unique_address</span><span class="op">]]</span> LayoutMapping mapping <span class="op">=</span> LayoutMapping<span class="op">()</span>;</span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">size_t</span> offset<span class="op">{}</span>;</span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<code>submdspan_mapping_result</code> has the data members and special
members specified above. It has no base classes or members other than
those specified.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<code>LayoutMapping</code> shall meet the layout mapping
requirements.</p>
<p><b>24.7.3.7.4 Exposition-only helpers
[mdspan.submdspan.helpers]</b></p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-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="op">&gt;</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> T <em>de-ice</em><span class="op">(</span>T val<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> val; <span class="op">}</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>integral-constant-like</em> T<span class="op">&gt;</span></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> <em>de-ice</em><span class="op">(</span>T<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> T<span class="op">::</span>value; <span class="op">}</span></span></code></pre></div>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> IndexType, <span class="dt">size_t</span> k, <span class="kw">class</span> <span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> IndexType <em>first</em>_<span class="op">(</span>SliceSpecifiers<span class="op">...</span> slices<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Mandates:</em> <code>IndexType</code> is a signed or unsigned
integer type.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Let <span class="math inline"><em>φ</em><sub><em>k</em></sub></span>
denote the following value:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<span class="math inline"><em>s</em><sub><em>k</em></sub></span> if
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<code>convertible_to&lt;IndexType&gt;</code>; otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>get&lt;0&gt;(</code> <span class="math inline"><em>s</em><sub><em>k</em></sub></span>
<code>)</code> if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;IndexType&gt;</code>;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<em><code>de-ice</code></em><code>(</code><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.offset)</code>
if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code>; otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span>
<code>0</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Preconditions:</em> <span class="math inline"><em>φ</em><sub><em>k</em></sub></span> is
representable as a value of type <code>IndexType</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Returns:</em>
<code>extents&lt;IndexType&gt;::</code><em><code>index-cast</code></em><code>(</code>
<span class="math inline"><em>φ</em><sub><em>k</em></sub></span>
<code>)</code>.</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> k, <span class="kw">class</span> Extents, <span class="kw">class</span> <span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> <em>last</em>_<span class="op">(</span><span class="kw">const</span> Extents<span class="op">&amp;</span> src, SliceSpecifiers<span class="op">...</span> slices<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Mandates:</em> <code>Extents</code> is a specialization of
<code>extents</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
Let <code>index_type</code> name the type
<code>typename Extents::index_type</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
Let <span class="math inline"><em>λ</em><sub><em>k</em></sub></span>
denote the following value:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.1)</a></span>
<em><code>de-ice</code></em><code>(</code><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>) + 1</code>
if <span class="math inline"><em>S</em><sub><em>k</em></sub></span>
models <code>convertible_to&lt;index_type&gt;</code>; otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.2)</a></span>
<code>get&lt;1&gt;(</code> <span class="math inline"><em>s</em><sub><em>k</em></sub></span>
<code>)</code> if <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>;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.3)</a></span>
<em><code>de-ice</code></em><code>(</code><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.offset) +</code><em><code>de-ice</code></em><code>(</code><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.extent)</code>
if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code>; otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.4)</a></span>
<code>src.extent(k)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Preconditions:</em> <span class="math inline"><em>λ</em><sub><em>k</em></sub></span> is
representable as a value of type <code>index_type</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Returns:</em>
<code>Extents::</code><em><code>index-cast</code></em><code>(</code>
<span class="math inline"><em>λ</em><sub><em>k</em></sub></span>
<code>)</code>.</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> IndexType, <span class="dt">size_t</span> N, <span class="kw">class</span> <span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> array<span class="op">&lt;</span>IndexType, <span class="kw">sizeof</span><span class="op">...(</span>SliceSpecifiers<span class="op">)&gt;</span></span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a>  <em>src-indices</em><span class="op">(</span><span class="kw">const</span> array<span class="op">&lt;</span>IndexType, N<span class="op">&gt;&amp;</span> indices, SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Mandates:</em> <code>IndexType</code> is a signed or unsigned
integer type.</p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Returns:</em> an
<code>array&lt;IndexType, sizeof...(SliceSpecifiers)&gt;</code>
<code>src_idx</code> such that for each <code>k</code> in the range of
<span class="math inline">[</span> 0,
<code>sizeof...(SliceSpecifiers)</code> <span class="math inline">)</span> <code>src_idx[k]</code> equals</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span>
<em><code>first</code></em><code>_&lt;IndexType, k&gt;(slices...)</code>
for each <code>k</code> where
<em><code>map-rank</code></em><code>[k]</code> equals
<code>dynamic_extent</code>, otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.2)</a></span>
<em><code>first</code></em><code>_&lt;IndexType, k&gt;(slices...) + indices[</code><em><code>map-rank</code></em><code>[k]]</code>.</p></li>
</ul>
<p><b>24.7.3.7.4 <code>submdspan_extents</code> function
[mdspan.submdspan.extents]</b></p>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> IndexType, <span class="kw">class</span> <span class="op">...</span> Extents, <span class="kw">class</span> <span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> submdspan_extents<span class="op">(</span><span class="kw">const</span> extents<span class="op">&lt;</span>IndexType, Extents<span class="op">...&gt;&amp;</span> src, SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Constraints:</em> <code>sizeof...(slices)</code> equals
<code>Extents::rank()</code>,</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates:</em> For each rank index <code>k</code> of
<code>src.extents()</code>, exactly one of the following is true:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<code>convertible_to&lt;IndexType&gt;</code></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;IndexType&gt;</code></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span>
<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></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.4)</a></span>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code></p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Preconditions:</em> For each rank index <code>k</code> of
<code>src.extents()</code>, all of the following are true:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span> if
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code></p>
<ul>
<li><p><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.extent</code>
<span class="math inline"> = 0</span>, or</p></li>
<li><p><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.stride</code>
<span class="math inline"> &gt; 0</span></p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<span class="math inline">0≤</span>
<em><code>first</code></em><code>_&lt;IndexType, k&gt;(slices...)</code>
<span class="math inline">≤</span>
<em><code>last_&lt;k&gt;</code></em><code>(src, slices...)</code> <span class="math inline">≤</span> <code>src.extent(k)</code></p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Let <code>SubExtents</code> be a specialization of <code>extents</code>
such that:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>SubExtents::rank()</code> equals the number of <span class="math inline"><em>k</em></span> such that <span class="math inline"><em>S</em><sub><em>k</em></sub></span> does not
model <code>convertible_to&lt;IndexType&gt;</code>; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> for
all rank index <code>k</code> of <code>Extents</code> such that
<em><code>map-rank</code></em><code>[k] != dynamic_extent</code> is
<code>true</code>,
<code>SubExtents::static_extent(</code><em><code>map-rank</code></em><code>[k])</code>
equals:</p>
<ul>
<li><p><code>Extents::static_extent(k)</code> if
<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>; otherwise</p></li>
<li><p><em><code>de-ice</code></em><code>(tuple_element_t&lt;1,</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>&gt;()) -</code>
<em><code>de-ice</code></em><code>(tuple_element_t&lt;0,</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>&gt;())</code>
if <span class="math inline"><em>S</em><sub><em>k</em></sub></span>
models
<em><code>index-pair-like</code></em><code>&lt;IndexType&gt;</code>, and
both <code>tuple_element_t&lt;0,</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>&gt;</code>
and <code>tuple_element_t&lt;1,</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>&gt;</code>
model <em><code>integral-constant-like</code></em>; otherwise</p></li>
<li><p><code>0</code>, if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code>, whose
<code>extent_type</code> models
<em><code>integral-constant-like</code></em>, for which
<code>extent_type()</code> equals zero; otherwise</p></li>
<li><p><code>1 + (</code>
<em><code>de-ice</code></em><code>(</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>::extent_type()) - 1) /</code><em><code>de-ice</code></em><code>(</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>::stride_type())</code>
if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code>, whose
<code>extent_type</code> and <code>stride_type</code> model
<em><code>integral-constant-like</code></em>; otherwise</p></li>
<li><p><code>dynamic_extent</code>.</p></li>
</ul></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Returns:</em> A value <code>ext</code> of type
<code>SubExtents</code> such that for each <code>k</code> for which
<em><code>map-rank</code></em><code>[k] != dynamic_extent</code> is
<code>true</code>:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span>
<code>ext.extent(</code><em><code>map-rank</code></em><code>[k])</code>
equals <span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.extent == 0 ? 0 : 1 + (</code><em><code>de-ice</code></em><code>(</code><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.extent) - 1) /</code><em><code>de-ice</code></em><code>(</code><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.stride)</code>
if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code>, otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
<code>ext.extent(</code><em><code>map-rank</code></em><code>[k])</code>
equals
<em><code>last_&lt;k&gt;</code></em><code>(src, slices...) -</code><em><code>first</code></em><code>_&lt;IndexType, k&gt;(slices...)</code>.</p></li>
</ul>
<p><b>24.7.3.7.5 Layout specializations of
<code>submdspan_mapping</code> [mdspan.submdspan.mapping]</b></p>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> layout_left<span class="op">::</span>mapping<span class="op">&lt;</span>Extents<span class="op">&gt;::</span><em>submdspan-mapping-impl</em><span class="op">(</span>    <span class="co">// <em>exposition only</em></span></span>
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a>    SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span>
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb31-8"><a href="#cb31-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> layout_right<span class="op">::</span>mapping<span class="op">&lt;</span>Extents<span class="op">&gt;::</span><em>submdspan-mapping-impl</em><span class="op">(</span>   <span class="co">// <em>exposition only</em></span></span>
<span id="cb31-9"><a href="#cb31-9" aria-hidden="true" tabindex="-1"></a>    SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span>
<span id="cb31-10"><a href="#cb31-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb31-11"><a href="#cb31-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb31-12"><a href="#cb31-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb31-13"><a href="#cb31-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> layout_stride<span class="op">::</span>mapping<span class="op">&lt;</span>Extents<span class="op">&gt;::</span><em>submdspan-mapping-impl</em><span class="op">(</span>  <span class="co">// <em>exposition only</em></span></span>
<span id="cb31-14"><a href="#cb31-14" aria-hidden="true" tabindex="-1"></a>    SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Let <code>index_type</code> name the type
<code>typename Extents::index_type</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> <code>sizeof...(slices)</code> equals
<code>Extents::rank()</code>,</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> For each rank index <code>k</code> of
<code>extents()</code>, exactly one of the following is true:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<code>convertible_to&lt;index_type&gt;</code></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<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></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span>
<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></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.4)</a></span>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code></p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Preconditions:</em> For each rank index <code>k</code> of
<code>extents()</code>, all of the following are true:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> if
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code></p>
<ul>
<li><p><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.extent</code>
<span class="math inline"> = 0</span>, or</p></li>
<li><p><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.stride</code>
<span class="math inline"> &gt; 0</span></p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
<span class="math inline">0≤</span>
<em><code>first</code></em><code>_&lt;index_type, k&gt;(slices...)</code>
<span class="math inline">≤</span>
<em><code>last_&lt;k&gt;</code></em><code>(extents(), slices...)</code>
<span class="math inline">≤</span>
<code>extents().extent(k)</code></p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
Let <code>sub_ext</code> be the result of
<code>submdspan_extents(extents(), slices...)</code> and let
<code>SubExtents</code> be <code>decltype(sub_ext)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
Let <code>sub_strides</code> be an
<code>array&lt;SubExtents::index_type, SubExtents::rank()&gt;</code>
such that for each rank index <code>k</code> of <code>extents()</code>
for which <em><code>map-rank</code></em><code>[k]</code> is not
<code>dynamic_extent</code>,
<code>sub_strides[</code><em><code>map-rank</code></em><code>[k]]</code>
equals:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span>
<code>stride(k) *</code><em><code>de-ice</code></em><code>(</code><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.stride)</code>
if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code> and <span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.stride</code>
<span class="math inline"> &lt; <em>s</em><sub><em>k</em></sub></span><code>.extent</code>;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span>
<code>stride(k)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
Let <code>P</code> be a parameter pack such that
<code>is_same_v&lt;make_index_sequence&lt;rank()&gt;, index_sequence&lt;P...&gt;&gt;</code>
is <code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
Let <code>offset</code> be a value of type <code>size_t</code> equal to
<code>(*this)(</code><em><code>first</code></em><code>_&lt;index_type, P&gt;(slices...)...)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
<code>submdspan_mapping_result{*this, 0}</code>, if
<code>Extents::rank()==0</code> is <code>true</code>; otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span>
<code>submdspan_mapping_result{layout_left::mapping(sub_ext), offset}</code>,
if</p>
<ul>
<li><p><code>layout_type</code> is <code>layout_left</code>;
and</p></li>
<li><p>for each <code>k</code> in the range <span class="math inline">[0,</span> <code>SubExtents::rank()-1</code><span class="math inline">)</span>, <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>; and</p></li>
<li><p>for <code>k</code> equal to <code>SubExtents::rank()-1</code>,
<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>; otherwise</p></li>
</ul>
<p><i>[Note: </i> If the above conditions are true, all <span class="math inline"><em>S</em><sub><em>k</em></sub></span> with
<code>k</code> larger than <code>SubExtents::rank()-1</code> are
convertible to <code>index_type</code>. <i>- end note]</i></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.3)</a></span>
<code>submdspan_mapping_result{layout_right::mapping(sub_ext), offset}</code>,
if</p>
<ul>
<li><p><code>layout_type</code> is <code>layout_right</code>;
and</p></li>
<li><p>for each <code>k</code> in the range <span class="math inline">[</span>
<code>Extents::rank() - SubExtents::rank()+1, Extents::rank()</code><span class="math inline">)</span>, <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>; and</p></li>
<li><p>for <code>k</code> equal to
<code>Extents::rank()-SubExtents::rank()</code>, <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>; otherwise</p></li>
</ul>
<p><i>[Note: </i> If the above conditions are true, all <span class="math inline"><em>S</em><sub><em>k</em></sub></span> with
<code>k</code> <span class="math inline">&lt;</span>
<code>Extents::rank()-SubExtents::rank()</code> are convertible to
<code>index_type</code>. <i>- end note]</i></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.4)</a></span>
<code>submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}</code>.</p></li>
</ul>
<p><b>24.7.3.7.6 <code>submdspan</code> function
[mdspan.submdspan.submdspan]</b></p>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="co">// [mdspan.submdspan], submdspan creation</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="kw">class</span> Extents, <span class="kw">class</span> LayoutPolicy,</span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> AccessorPolicy, <span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb32-4"><a href="#cb32-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan<span class="op">(</span></span>
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> mdspan<span class="op">&lt;</span>ElementType, Extents, LayoutPolicy, AccessorPolicy<span class="op">&gt;&amp;</span> src,</span>
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a>    SliceSpecifiers<span class="op">...</span>slices<span class="op">)</span> <span class="op">-&gt;</span> <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
Let <code>index_type</code> name the type
<code>typename Extents::index_type</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Let <code>sub_map_offset</code> be the result of
<code>submdspan_mapping(src.mapping(), slices...)</code>. <i>[Note: </i>
This invocation of <code>submdspan_mapping</code> selects a function
call via overload resolution on a candidate set that includes the lookup
set found by argument dependent lookup ([basic.lookup.argdep]). <i>- end
note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<code>sizeof...(slices)</code> equals <code>Extents::rank()</code>,
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> the
expression <code>submdspan_mapping(src.mapping(), slices...)</code> is
well-formed when treated as an unevaluated operand.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Mandates:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>decltype(submdspan_mapping(src.mapping(), slices...))</code> is a
specialization of <code>submdspan_mapping_result</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
<code>is_same_v&lt;remove_cvref_t&lt;decltype(sub_map_offset.mapping.extents())&gt;, decltype(submdspan_extents(src.mapping(), slices...))&gt;</code>
is <code>true</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span> For
each rank index <code>k</code> of <code>src.extents()</code>, exactly
one of the following is true:</p>
<ul>
<li><p><span class="math inline"><em>S</em><sub><em>k</em></sub></span>
models <code>convertible_to&lt;index_type&gt;</code></p></li>
<li><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></p></li>
<li><p><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></li>
<li><p><span class="math inline"><em>S</em><sub><em>k</em></sub></span>
is a specialization of <code>strided_slice</code></p></li>
</ul></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> For
each rank index <code>k</code> of <code>src.extents()</code>, all of the
following are true:</p>
<ul>
<li><p>if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code></p>
<ul>
<li><p><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.extent</code>
<span class="math inline"> = 0</span>, or</p></li>
<li><p><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.stride</code>
<span class="math inline"> &gt; 0</span></p></li>
</ul></li>
<li><p><span class="math inline">0≤</span>
<em><code>first</code></em><code>_&lt;index_type, k&gt;(slices...)</code>
<span class="math inline">≤</span>
<em><code>last_&lt;k&gt;</code></em><code>(src.extents(), slices...)</code>
<span class="math inline">≤</span> <code>src.extent(k)</code></p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
<code>sub_map_offset.mapping.extents() == submdspan_extents(src.mapping(), slices...)</code>
is <code>true</code>; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.3)</a></span> for
each integer pack <code>I</code> which is a multidimensional index in
<code>sub_map_offset.mapping.extents()</code>,
<code>sub_map_offset.mapping(I...) + sub_map_offset.offset == src.mapping()(</code><em><code>src-indices</code></em><code>(array{I...}, slices ...))</code>
is <code>true</code>.</p></li>
</ul>
<p><i>[Note: </i> These conditions ensure that the mapping returned by
<code>submdspan_mapping</code> matches the algorithmically expected
index-mapping given the slice specifiers. <i>- end note]</i></p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects:</em> Equivalent to</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-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>, args<span class="op">...)</span>;</span>
<span id="cb33-2"><a href="#cb33-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="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a>                sub_map_offset<span class="op">.</span>mapping,</span>
<span id="cb33-4"><a href="#cb33-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><i>[Example:</i></p>
<p>Given a rank-3 <code>mdspan</code> <code>grid3d</code> representing a
three-dimensional grid of regularly spaced points in a rectangular
prism, the function <code>zero_surface</code> sets all elements on the
surface of the 3-dimensional shape to zero. It does so by reusing a
function <code>zero_2d</code> that takes a rank-2
<code>mdspan</code>.</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="co">// zero out all elements in an mdspan</span></span>
<span id="cb34-2"><a href="#cb34-2" 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> E, <span class="kw">class</span> L, <span class="kw">class</span> A<span class="op">&gt;</span></span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> zero_2d<span class="op">(</span>mdspan<span class="op">&lt;</span>T,E,L,A<span class="op">&gt;</span> a<span class="op">)</span> <span class="op">{</span></span>
<span id="cb34-4"><a href="#cb34-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>a<span class="op">.</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> i<span class="op">=</span><span class="dv">0</span>; i<span class="op">&lt;</span>a<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; i<span class="op">++)</span></span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> j<span class="op">=</span><span class="dv">0</span>; j<span class="op">&lt;</span>a<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; j<span class="op">++)</span></span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a>      a<span class="op">[</span>i,j<span class="op">]</span> <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb34-8"><a href="#cb34-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb34-9"><a href="#cb34-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-10"><a href="#cb34-10" aria-hidden="true" tabindex="-1"></a><span class="co">// zero out just the surface</span></span>
<span id="cb34-11"><a href="#cb34-11" 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> E, <span class="kw">class</span> L, <span class="kw">class</span> A<span class="op">&gt;</span></span>
<span id="cb34-12"><a href="#cb34-12" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> zero_surface<span class="op">(</span>mdspan<span class="op">&lt;</span>T,E,L,A<span class="op">&gt;</span> grid3d<span class="op">)</span> <span class="op">{</span></span>
<span id="cb34-13"><a href="#cb34-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>grid3d<span class="op">.</span>rank<span class="op">()</span> <span class="op">==</span> <span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb34-14"><a href="#cb34-14" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, <span class="dv">0</span>, full_extent, full_extent<span class="op">))</span>;</span>
<span id="cb34-15"><a href="#cb34-15" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, full_extent, <span class="dv">0</span>, full_extent<span class="op">))</span>;</span>
<span id="cb34-16"><a href="#cb34-16" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, full_extent, full_extent, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb34-17"><a href="#cb34-17" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, grid3d<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)-</span><span class="dv">1</span>, full_extent, full_extent<span class="op">))</span>;</span>
<span id="cb34-18"><a href="#cb34-18" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, full_extent, grid3d<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)-</span><span class="dv">1</span>, full_extent<span class="op">))</span>;</span>
<span id="cb34-19"><a href="#cb34-19" aria-hidden="true" tabindex="-1"></a>  zero_2d<span class="op">(</span>submdspan<span class="op">(</span>grid3d, full_extent, full_extent, grid3d<span class="op">.</span>extent<span class="op">(</span><span class="dv">2</span><span class="op">)-</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb34-20"><a href="#cb34-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><i>- end example]</i></p>
</div>
</div>
</body>
</html>
