<!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" />
  <title>mdarray design questions and answers</title>
  <style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
  <style>
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ background-color: #f6f8fa; }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span { } 
code span.al { color: #ff0000; } 
code span.an { } 
code span.at { } 
code span.bn { color: #9f6807; } 
code span.bu { color: #9f6807; } 
code span.cf { color: #00607c; } 
code span.ch { color: #9f6807; } 
code span.cn { } 
code span.co { color: #008000; font-style: italic; } 
code span.cv { color: #008000; font-style: italic; } 
code span.do { color: #008000; } 
code span.dt { color: #00607c; } 
code span.dv { color: #9f6807; } 
code span.er { color: #ff0000; font-weight: bold; } 
code span.ex { } 
code span.fl { color: #9f6807; } 
code span.fu { } 
code span.im { } 
code span.in { color: #008000; } 
code span.kw { color: #00607c; } 
code span.op { color: #af1915; } 
code span.ot { } 
code span.pp { color: #6f4e37; } 
code span.re { } 
code span.sc { color: #9f6807; } 
code span.ss { color: #9f6807; } 
code span.st { color: #9f6807; } 
code span.va { } 
code span.vs { color: #9f6807; } 
code span.wa { color: #008000; font-weight: bold; } 
code.diff {color: #898887}
code.diff span.va {color: #00AA00}
code.diff span.st {color: #bf0303}
</style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

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

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

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

code.sourceCode > span { display: inline; }

div#refs p { padding-left: 32px; text-indent: -32px; }
</style>
  <link href="data:image/vnd.microsoft.icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center"><code>mdarray</code> design
questions and answers</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #: </td>
    <td>P3308R0</td>
  </tr>
  <tr>
    <td>Date: </td>
    <td>2024/05/21</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>
      Mark Hoemmen<br>&lt;<a href="mailto:mhoemmen@nvidia.com" class="email">mhoemmen@nvidia.com</a>&gt;<br>
      Christian Trott<br>&lt;<a href="mailto:crtrott@sandia.gov" class="email">crtrott@sandia.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="#authors" id="toc-authors"><span class="toc-section-number">1</span> Authors</a></li>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">2</span> Revision history</a></li>
<li><a href="#abstract" id="toc-abstract"><span class="toc-section-number">3</span> Abstract</a></li>
<li><a href="#summary-of-our-discussion-and-conclusions" id="toc-summary-of-our-discussion-and-conclusions"><span class="toc-section-number">4</span> Summary of our discussion and
conclusions</a>
<ul>
<li><a href="#discussions-requested-by-lewg" id="toc-discussions-requested-by-lewg"><span class="toc-section-number">4.1</span> Discussions requested by
LEWG</a></li>
<li><a href="#our-conclusions" id="toc-our-conclusions"><span class="toc-section-number">4.2</span> Our conclusions</a></li>
<li><a href="#revisions-requested-by-lewg" id="toc-revisions-requested-by-lewg"><span class="toc-section-number">4.3</span> Revisions requested by
LEWG</a></li>
<li><a href="#other-topics-we-discuss" id="toc-other-topics-we-discuss"><span class="toc-section-number">4.4</span> Other topics we discuss</a></li>
</ul></li>
<li><a href="#construction-from-a-c-array" id="toc-construction-from-a-c-array"><span class="toc-section-number">5</span> Construction from a C array</a></li>
<li><a href="#add-in_place_t-constructors" id="toc-add-in_place_t-constructors"><span class="toc-section-number">6</span> Add <code>in_place_t</code>
constructors</a>
<ul>
<li><a href="#summary" id="toc-summary"><span class="toc-section-number">6.1</span> Summary</a></li>
<li><a href="#let-mdarray-construct-its-container" id="toc-let-mdarray-construct-its-container"><span class="toc-section-number">6.2</span> Let <code>mdarray</code> construct
its container</a></li>
<li><a href="#what-would-in_place_t-constructors-look-like" id="toc-what-would-in_place_t-constructors-look-like"><span class="toc-section-number">6.3</span> What would <code>in_place_t</code>
constructors look like?</a></li>
</ul></li>
<li><a href="#remove-const-container_type-and-container_type-constructors" id="toc-remove-const-container_type-and-container_type-constructors"><span class="toc-section-number">7</span> Remove
<code>const container_type&amp;</code> and
<code>container_type&amp;&amp;</code> constructors</a></li>
<li><a href="#do-not-add-separate-constructors-from-flat-initializer-list" id="toc-do-not-add-separate-constructors-from-flat-initializer-list"><span class="toc-section-number">8</span> Do not add separate constructors
from “flat” initializer list</a></li>
<li><a href="#consider-adding-construction-from-nested-initializer-list" id="toc-consider-adding-construction-from-nested-initializer-list"><span class="toc-section-number">9</span> Consider adding construction from
nested initializer list</a>
<ul>
<li><a href="#why-we-want-this" id="toc-why-we-want-this"><span class="toc-section-number">9.1</span> Why we want this</a></li>
<li><a href="#limits-of-this-approach" id="toc-limits-of-this-approach"><span class="toc-section-number">9.2</span> Limits of this approach</a></li>
<li><a href="#alternative-make_mdarray-function" id="toc-alternative-make_mdarray-function"><span class="toc-section-number">9.3</span> Alternative:
<code>make_mdarray</code> function</a></li>
<li><a href="#implementation-approach" id="toc-implementation-approach"><span class="toc-section-number">9.4</span> Implementation approach</a></li>
</ul></li>
<li><a href="#add-an-executionpolicy-overload-to-construction-from-mdspan" id="toc-add-an-executionpolicy-overload-to-construction-from-mdspan"><span class="toc-section-number">10</span> Add an
<code>ExecutionPolicy&amp;&amp;</code> overload to construction from
<code>mdspan</code></a></li>
<li><a href="#why-mdarray-is-a-container-adapter-and-not-a-container" id="toc-why-mdarray-is-a-container-adapter-and-not-a-container"><span class="toc-section-number">11</span> Why <code>mdarray</code> is a
container adapter and not a container</a>
<ul>
<li><a href="#consistency-with-mdspan" id="toc-consistency-with-mdspan"><span class="toc-section-number">11.1</span> Consistency with
<code>mdspan</code></a></li>
<li><a href="#what-would-a-container-design-look-like" id="toc-what-would-a-container-design-look-like"><span class="toc-section-number">11.2</span> What would a container design
look like?</a></li>
<li><a href="#advantages-of-a-container-design" id="toc-advantages-of-a-container-design"><span class="toc-section-number">11.3</span> Advantages of a container
design</a></li>
<li><a href="#disadvantages-of-a-container-design" id="toc-disadvantages-of-a-container-design"><span class="toc-section-number">11.4</span> Disadvantages of a container
design</a></li>
<li><a href="#no-major-notational-advantages" id="toc-no-major-notational-advantages"><span class="toc-section-number">11.5</span> No major notational
advantages</a></li>
</ul></li>
</ul>
</div>
<h1 data-number="1" id="authors"><span class="header-section-number">1</span> Authors<a href="#authors" class="self-link"></a></h1>
<ul>
<li><p>Mark Hoemmen (mhoemmen@nvidia.com) (NVIDIA)</p></li>
<li><p>Christian Trott (crtrott@sandia.gov) (Sandia National
Laboratories)</p></li>
</ul>
<h1 data-number="2" id="revision-history"><span class="header-section-number">2</span> Revision history<a href="#revision-history" class="self-link"></a></h1>
<ul>
<li>Revision 0 (pre-St. Louis) to be submitted 2024/05/21</li>
</ul>
<h1 data-number="3" id="abstract"><span class="header-section-number">3</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>This paper responds to LEWG’s review of P1684R5
(“<code>mdarray</code>: An Owning Multidimensional Array Analog of
<code>mdspan</code>”). It discusses topics that LEWG asked the P1684R5
authors to discuss, and also answers some design questions that the
authors have asked themselves. We present this discussion in a way that
we hope will help WG21 understand the design motivations of
<code>mdarray</code>. In order to make this presentation as clear as
possible, we have submitted it as a separate paper, rather than as a
revision of P1684. We hope that WG21 has the opportunity and interest to
read and discuss this paper, and give us feedback to help us improve
P1684.</p>
<h1 data-number="4" id="summary-of-our-discussion-and-conclusions"><span class="header-section-number">4</span> Summary of our discussion and
conclusions<a href="#summary-of-our-discussion-and-conclusions" class="self-link"></a></h1>
<h2 data-number="4.1" id="discussions-requested-by-lewg"><span class="header-section-number">4.1</span> Discussions requested by LEWG<a href="#discussions-requested-by-lewg" class="self-link"></a></h2>
<p>LEWG, during its review of P1684R5, asked the authors to consider or
discuss the following points.</p>
<ol type="1">
<li><p>Consider adding a constructor from a (possibly multidimensional)
C array</p></li>
<li><p>Consider adding <code>in_place_t</code> constructors (that
forward their arguments to the container’s constructor), so that
<code>mdarray</code> can construct the container in place without a copy
or move</p></li>
<li><p>Discuss construction from initializer lists</p></li>
</ol>
<h2 data-number="4.2" id="our-conclusions"><span class="header-section-number">4.2</span> Our conclusions<a href="#our-conclusions" class="self-link"></a></h2>
<p>We think that P1684 should be revised to make the following
changes.</p>
<ol type="1">
<li><p>Add constructors from (possibly multidimensional) C arrays, and
corresponding deduction guides, to <code>mdarray</code>.</p></li>
<li><p>Add <code>in_place_t</code> constructors and corresponding
deduction guides. This would also let users construct
<code>mdarray</code> from an extents or mapping object, along with a
“flat” (one-dimensional) initializer list of values. It would also let
us remove wording for <em>all</em> the constructors that take
<code>const container_type&amp;</code> or
<code>container_type&amp;&amp;</code>.</p></li>
<li><p>Consider adding multidimensional nested
<code>initializer_list</code> constructors and deduction guides. This
would enable Matlab- or Python-like <code>mdarray</code>
construction.</p></li>
</ol>
<h2 data-number="4.3" id="revisions-requested-by-lewg"><span class="header-section-number">4.3</span> Revisions requested by LEWG<a href="#revisions-requested-by-lewg" class="self-link"></a></h2>
<p>LEWG has also asked for the following revisions:</p>
<ol type="1">
<li><p>addition of a feature test macro,</p></li>
<li><p>a description of how to format an <code>mdarray</code>,
and</p></li>
<li><p>“the necessary preconditions to avoid use of an object in an
invalid state.”</p></li>
</ol>
<p>We think (2) is best addressed by describing how to format
<code>mdspan</code>. That would solve a more general problem. A future
revision of P1684 will address (1) and (3). We personally would prefer
that <code>mdarray</code> forbid construction from a moved-from
container, and that the only valid <code>mdarray</code> operation after
moving from that <code>mdarray</code> should be destruction.</p>
<h2 data-number="4.4" id="other-topics-we-discuss"><span class="header-section-number">4.4</span> Other topics we discuss<a href="#other-topics-we-discuss" class="self-link"></a></h2>
<ol type="1">
<li><p>In order for the <code>mdarray</code> constructor that takes
<code>mdspan</code> to know how to do multidimensional copy in parallel,
we should consider adding an <code>ExecutionPolicy&amp;&amp;</code>
overload to the <code>mdarray</code> constructor that takes
<code>mdspan</code>. On the other hand, adding <code>in_place_t</code>
constructors to <code>mdarray</code> means that if users have a custom
container that can be constructed directly from <code>mdspan</code>
efficiently, then that container would solve any performance issues
resulting from constructing an <code>mdarray</code> from an
<code>mdspan</code>.</p></li>
<li><p>We summarize arguments for and against changing from the R5
container adapter design to a container design, and conclude that the
reasons for change do not outweigh the status quo (that is, that
<code>mdarray</code> should remain a container adapter).</p></li>
</ol>
<h1 data-number="5" id="construction-from-a-c-array"><span class="header-section-number">5</span> Construction from a C array<a href="#construction-from-a-c-array" class="self-link"></a></h1>
<p>We have implemented <code>mdarray</code> CTAD (constructor template
argument deduction) from a possibly multidimensional C array. Here is a
pull request that adds the necessary constructor and deduction guide, so
you can construct an <code>mdarray</code> (with CTAD that deduces
<code>container_type = std::array</code>) from a possibly
multidimensional C array: https://github.com/kokkos/mdspan/pull/329
.</p>
<p>The change includes a new <code>mdarray</code> constructor,</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="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> CArray<span class="op">&gt;</span> <span class="kw">requires</span> <span class="op">(</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>is_array_v<span class="op">&lt;</span>CArray<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>rank_v<span class="op">&lt;</span>CArray<span class="op">&gt;</span> <span class="op">&gt;=</span> <span class="dv">1</span><span class="bu">u</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> mdarray<span class="op">(</span>CArray<span class="op">&amp;</span> values<span class="op">)</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">:</span> map_<span class="op">(</span>extents_type<span class="op">{})</span>, ctr_<span class="op">{</span>impl<span class="op">::</span>carray_to_array<span class="op">(</span>values<span class="op">)}</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="op">{}</span></span></code></pre></div>
<p>and a new <code>mdarray</code> deduction guide.</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> CArray<span class="op">&gt;</span> <span class="kw">requires</span> <span class="op">(</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>is_array_v<span class="op">&lt;</span>CArray<span class="op">&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>rank_v<span class="op">&lt;</span>CArray<span class="op">&gt;</span> <span class="op">&gt;=</span> <span class="dv">1</span><span class="bu">u</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>mdarray<span class="op">(</span>CArray<span class="op">&amp;</span> values<span class="op">)</span> <span class="op">-&gt;</span> mdarray<span class="op">&lt;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>remove_all_extents_t<span class="op">&lt;</span>CArray<span class="op">&gt;</span>,</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">decltype</span><span class="op">(</span>impl<span class="op">::</span>extents_of_carray<span class="op">(</span>values<span class="op">))</span>,</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  layout_right,</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">decltype</span><span class="op">(</span>impl<span class="op">::</span>carray_to_array<span class="op">(</span>values<span class="op">))</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span>;</span></code></pre></div>
<p>The new <code>mdarray</code> constructor deep-copies the input (as
<code>mdarray</code> is a container, not a view). Note that
<code>mdspan</code> has a deduction guide for construction from a
one-dimensional C array. However, <code>mdspan</code> <em>cannot</em> do
this for the multidimensional case, because the Standard does not permit
conversion of a multidimensional C array to a pointer (or
one-dimensional C array). <code>mdarray</code> can do this because
<code>mdarray</code> deep-copies its input array.</p>
<h1 data-number="6" id="add-in_place_t-constructors"><span class="header-section-number">6</span> Add <code>in_place_t</code>
constructors<a href="#add-in_place_t-constructors" class="self-link"></a></h1>
<h2 data-number="6.1" id="summary"><span class="header-section-number">6.1</span> Summary<a href="#summary" class="self-link"></a></h2>
<p>Adding <code>in_place_t</code> constructors that forward arguments to
<code>container_type</code>’s constructor would let <code>mdarray</code>
construct its container in place. This would be a truly zero-overhead
abstraction for many use cases. The constructors would still need to
take an <code>extents_type</code> or <code>mapping_type</code> parameter
as well as the in-place parameters, in order to interpret the flat
container as a multidimensional array. Adding these
<code>in_place_t</code> constructors, along with corresponding deduction
guides, could replace the functionality of all the constructors taking
<code>const container_type&amp;</code> or
<code>container_type&amp;&amp;</code>, and would thus let us remove the
latter constructors. This would simplify the wording while only slightly
increasing verbosity for users.</p>
<h2 data-number="6.2" id="let-mdarray-construct-its-container"><span class="header-section-number">6.2</span> Let <code>mdarray</code>
construct its container<a href="#let-mdarray-construct-its-container" class="self-link"></a></h2>
<p><code>mdarray</code> currently constructs its container in two ways.
(This ignores construction from <code>mdspan</code>, which we will
discuss below.)</p>
<ol type="1">
<li><p>Construction with the number of elements, and optionally one or
both of</p>
<ol type="a">
<li><p>a single default value with which to fill all of those elements,
or</p></li>
<li><p>an allocator</p></li>
</ol></li>
<li><p>Copy or move construction of the container itself, possibly also
with an allocator</p></li>
</ol>
<p>Currently, users who want the container to have a given list of
values at construction time must create the container themselves with an
initializer list argument, and pass the container into
<code>mdarray</code>’s constructor. The following example constructs an
<code>mdarray&lt;float, dims&lt;2&gt;, layout_right, std::array&lt;float&gt;&gt;</code>
representing a 2 by 3 matrix.</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>mdarray m<span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>,</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>array<span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>, <span class="co">// first row</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span>  <span class="co">// second row</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Even without CTAD, the constructor’s arguments would not change.</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>mdarray<span class="op">&lt;</span><span class="dt">float</span>, dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>, std<span class="op">::</span>array<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;&gt;</span> m<span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>,</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>array<span class="op">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>, <span class="co">// first row</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span>  <span class="co">// second row</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>This is because <code>mdarray</code> does not currently have a way
for users to construct the container in place, e.g., by passing in
values via <code>initializer_list</code>. Making the user construct a
temporary container poses a performance issue, at least in theory. This
issue comes up for all different ways that users might want to construct
the container, not just for construction from an initializer list of
values. <code>mdarray</code> is a container adapter; it permits
containers with possibly arbitrary constructors that are not covered by
the <code>vector</code>-like “size, initial value, and/or allocator”
cases.</p>
<p>Adding <code>in_place_t</code> constructors to <code>mdarray</code>
would make it possible for users to construct the container in place in
the <code>mdarray</code>, with possibly arbitrary arguments. This would
be a guaranteed zero-overhead abstraction, whereas creating a temporary
container might not be.</p>
<h2 data-number="6.3" id="what-would-in_place_t-constructors-look-like"><span class="header-section-number">6.3</span> What would
<code>in_place_t</code> constructors look like?<a href="#what-would-in_place_t-constructors-look-like" class="self-link"></a></h2>
<p>We can look at the existing C++ Standard Library classes with
<code>in_place_t</code> constructors as a model for adding them to
<code>mdarray</code>. These classes include</p>
<ul>
<li><code>any</code>,</li>
<li><code>expected</code>,</li>
<li><code>optional</code>, and</li>
<li><code>variant</code>.</li>
</ul>
<p>They have in common that they hold at most one object of some type
<code>T</code>, and they need to construct an instance of
<code>T</code>. We can look at the most recently added class template
<code>expected</code> for the general pattern, if we ignore the
“<code>T</code> is <em>cv</em> <code>void</code>” case (which doesn’t
apply to <code>mdarray</code>). <code>expected</code> has two
<code>in_place_t</code> constructors.</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">template</span><span class="op">&lt;</span> <span class="kw">class</span><span class="op">...</span> Args <span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>expected<span class="op">(</span>std<span class="op">::</span>in_place_t,</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span> <span class="kw">class</span> U, <span class="kw">class</span><span class="op">...</span> Args <span class="op">&gt;</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>expected<span class="op">(</span>std<span class="op">::</span>in_place_t,</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>initializer_list<span class="op">&lt;</span>U<span class="op">&gt;</span> il,</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>  Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span></code></pre></div>
<p>For <code>mdarray</code>, the <code>in_place_t</code> constructors
could not just take the arguments for the container. They would also
need to take the extents or mapping, in order to interpret the flat
container as a <code>rank()</code>-dimensional array. In order not to
confuse the extents or mapping with the constructor arguments, we would
end up with the following four constructors.</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">template</span><span class="op">&lt;</span> <span class="kw">class</span><span class="op">...</span> Args <span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span> mdarray<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> exts,</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>in_place_t,</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-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> Args <span class="op">&gt;</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span> mdarray<span class="op">(</span><span class="kw">const</span> mapping_type<span class="op">&amp;</span> mapping,</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>in_place_t,</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>  Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span> <span class="kw">class</span> U, <span class="kw">class</span><span class="op">...</span> Args <span class="op">&gt;</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span> mdarray<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> exts,</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>in_place_t,</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>initializer_list<span class="op">&lt;</span>U<span class="op">&gt;</span> il,</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>  Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span> <span class="kw">class</span> U, <span class="kw">class</span><span class="op">...</span> Args <span class="op">&gt;</span></span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span> mdarray<span class="op">(</span><span class="kw">const</span> mapping_type<span class="op">&amp;</span> mapping,</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>in_place_t,</span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>initializer_list<span class="op">&lt;</span>U<span class="op">&gt;</span> il,</span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a>  Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span></code></pre></div>
<p>The first two constructors would require that
<code>container_type</code> is constructible from <code>Args...</code>,
while the next two would require that <code>container_type</code> is
constructible from
<code>std::initializer_list&lt;U&gt;&amp;, Args...</code>.</p>
<p>This would be a novel use of <code>in_place_t</code>. All other
Standard Library classes use <code>in_place_t</code> for a type that
contains at most one thing and needs to construct the thing.
<code>mdarray</code> contains a layout mapping as well as the container.
On the other hand, it’s unambiguous that <code>mdarray</code> would
construct the layout mapping from an <code>extents_type</code> or
<code>mapping_type</code>, so it’s reasonable to put that parameter
first, before the <code>in_place_t</code> parameter.</p>
<p>Note that these <code>in_place_t</code> constructors would need
corresponding deduction guides in order for CTAD to work as expected.
Here ( https://godbolt.org/z/MPhEKKdaG ) is a brief demo, and here are
the required deduction guides.</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">template</span><span class="op">&lt;</span><span class="kw">class</span> ValueType, <span class="kw">class</span> IndexType, <span class="dt">size_t</span> <span class="op">...</span> Exts, <span class="kw">class</span> ContainerType<span class="op">&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>mdarray<span class="op">(</span><span class="kw">const</span> extents<span class="op">&lt;</span>IndexType, Exts<span class="op">...&gt;&amp;</span>, in_place_t, <span class="kw">const</span> ContainerType<span class="op">&amp;)</span> <span class="op">-&gt;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>  mdarray<span class="op">&lt;</span>ValueType, extents<span class="op">&lt;</span>IndexType, Exts<span class="op">...&gt;</span>, layout_right, ContainerType<span class="op">&gt;</span>;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ValueType, <span class="kw">class</span> IndexType, <span class="dt">size_t</span> <span class="op">...</span> Exts, <span class="kw">class</span> ContainerType<span class="op">&gt;</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>mdarray<span class="op">(</span><span class="kw">const</span> extents<span class="op">&lt;</span>IndexType, Exts<span class="op">...&gt;&amp;</span>, in_place_t, ContainerType<span class="op">&amp;&amp;)</span> <span class="op">-&gt;</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>  mdarray<span class="op">&lt;</span>ValueType, extents<span class="op">&lt;</span>IndexType, Exts<span class="op">...&gt;</span>, layout_right, ContainerType<span class="op">&gt;</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ValueType, <span class="kw">class</span> Layout, <span class="kw">class</span> IndexType, std<span class="op">::</span><span class="dt">size_t</span> <span class="op">...</span> Exts, <span class="kw">class</span> ContainerType<span class="op">&gt;</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>mdarray<span class="op">(</span><span class="kw">const</span> <span class="kw">typename</span> Layout<span class="op">::</span><span class="kw">template</span> mapping<span class="op">&lt;</span>extents<span class="op">&lt;</span>IndexType, Exts<span class="op">...&gt;&gt;&amp;</span>, in_place_t, <span class="kw">const</span> ContainerType<span class="op">&amp;)</span> <span class="op">-&gt;</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>  mdarray<span class="op">&lt;</span>ValueType, extents<span class="op">&lt;</span>IndexType, Exts<span class="op">...&gt;</span>, Layout, ContainerType<span class="op">&gt;</span>;</span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ValueType, <span class="kw">class</span> Layout, <span class="kw">class</span> IndexType, <span class="dt">size_t</span> <span class="op">...</span> Exts, <span class="kw">class</span> ContainerType<span class="op">&gt;</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>mdarray<span class="op">(</span><span class="kw">const</span> <span class="kw">typename</span> Layout<span class="op">::</span><span class="kw">template</span> mapping<span class="op">&lt;</span>extents<span class="op">&lt;</span>IndexType, Exts<span class="op">...&gt;&gt;&amp;</span>, in_place_t, ContainerType<span class="op">&amp;&amp;)</span> <span class="op">-&gt;</span></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>  mdarray<span class="op">&lt;</span>ValueType, extents<span class="op">&lt;</span>IndexType, Exts<span class="op">...&gt;</span>, Layout, ContainerType<span class="op">&gt;</span>;</span></code></pre></div>
<h1 data-number="7" id="remove-const-container_type-and-container_type-constructors"><span class="header-section-number">7</span> Remove
<code>const container_type&amp;</code> and
<code>container_type&amp;&amp;</code> constructors<a href="#remove-const-container_type-and-container_type-constructors" class="self-link"></a></h1>
<p>Adding the above <code>in_place_t</code> constructors, along with
corresponding deduction guides, would let us remove all the constructors
taking <code>const container_type&amp;</code> or
<code>container_type&amp;&amp;</code>. The result would make
<code>mdarray</code> much simpler, while only slightly increasing
verbosity for users. For example, the effect of the following
constructor in P1684R5</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>mdarray<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> exts, container_type<span class="op">&amp;&amp;</span> ctr, <span class="kw">const</span> Alloc<span class="op">&amp;</span> alloc<span class="op">)</span>;</span></code></pre></div>
<p>could be achieved by using the following <code>in_place_t</code>
constructor instead</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>mdarray<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> exts, in_place_t, Args<span class="op">&amp;&amp;...)</span>;</span></code></pre></div>
<p>and passing in the arguments like this.</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>mdarray<span class="op">&lt;</span> <span class="co">/* template arguments */</span> <span class="op">&gt;</span> m<span class="op">{</span>exts, in_place, std<span class="op">::</span>move<span class="op">(</span>ctr<span class="op">)</span>, alloc<span class="op">}</span>;</span></code></pre></div>
<p>The constructors of <code>mdarray</code> that take
<code>const container_type&amp;</code> or
<code>container_type&amp;&amp;</code> exist for a few reasons.</p>
<ol type="1">
<li><p>They enable CTAD for nondefault containers, such as
<code>array</code>.</p></li>
<li><p>They enable copying the values.</p></li>
<li><p>They pass along the container’s state, including any
allocator.</p></li>
<li><p>The constructors that move-construct the container allow using a
container as a kind of allocator for <code>mdarray</code>, that can be
passed along via <code>mdarray</code>’s <code>extract_container</code>
member function.</p></li>
</ol>
<p>Use case (1) is handy, especially for small arrays. It only requires
the constructors taking <code>container_type&amp;&amp;</code>, because
the typical use case is to construct the container in place as an
<code>mdarray</code> constructor argument, like this.</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>mdarray m<span class="op">{</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>,</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  array<span class="op">{</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>, <span class="co">// first row</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span>  <span class="co">// second row</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Replacing the <code>const extents_type&amp;</code>,
<code>container_type&amp;&amp;</code> constructor with a
<code>const extents_type&amp;</code>, <code>in_place_t</code>,
<code>Args&amp;&amp;...</code> constructor, and adding corresponding
deduction guides, would only make this a bit more verbose.</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>mdarray m<span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>, in_place,</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  array<span class="op">{</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>, <span class="co">// first row</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span>  <span class="co">// second row</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Adding the <code>in_place_t</code> constructors would satisfy use
cases (2) and (3) for any containers with a reasonable set of
constructors and access to members. Here is an example of use case (4),
the “passing along storage via container” use case that is the main
intended purpose of <code>extract_container</code> ( see
https://godbolt.org/z/MvxceW7rs for a quick demo). The
<code>in_place_t</code> constructor handles this use case as well, with
only a bit more verbosity.</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> ValueType, <span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>ValueType<span class="op">&gt;</span> use_vector<span class="op">(</span><span class="kw">const</span> Extents<span class="op">&amp;</span> exts, std<span class="op">::</span>vector<span class="op">&lt;</span>ValueType<span class="op">&gt;&amp;&amp;</span> x<span class="op">)</span> <span class="op">{</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> std<span class="op">::</span>layout_right;</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> container_type <span class="op">=</span> std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;</span>;</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> extents_type <span class="op">=</span> Extents;</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> mdarray_type <span class="op">=</span> mdarray<span class="op">&lt;</span>ValueType, extents_type, layout_right, container_type<span class="op">&gt;</span>;</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;use_vector: x.size() on input: &quot;</span> <span class="op">&lt;&lt;</span> x<span class="op">.</span>size<span class="op">()</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>    <span class="op">&lt;&lt;</span> <span class="st">&quot;; x.data(): &quot;</span> <span class="op">&lt;&lt;</span> x<span class="op">.</span>data<span class="op">()</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a>  layout_right<span class="op">::</span>mapping mapping<span class="op">{</span>exts<span class="op">}</span>;</span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">auto</span> size <span class="op">=</span> mapping<span class="op">.</span>required_span_size<span class="op">()</span>;</span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;  required_span_size: &quot;</span> <span class="op">&lt;&lt;</span> size <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span><span class="kw">static_cast</span><span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span><span class="op">&gt;(</span>size<span class="op">)</span> <span class="op">&gt;</span> x<span class="op">.</span>size<span class="op">())</span> <span class="op">{</span></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>resize<span class="op">(</span>size<span class="op">)</span>;</span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a>  mdarray_type x_md<span class="op">(</span>mapping, std<span class="op">::</span>in_place, std<span class="op">::</span>move<span class="op">(</span>x<span class="op">))</span>;</span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> std<span class="op">::</span>move<span class="op">(</span>x_md<span class="op">).</span>extract_container<span class="op">()</span>;</span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> stdex<span class="op">::</span>extents;</span>
<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;</span> storage<span class="op">(</span><span class="dv">6</span><span class="op">)</span>;</span>
<span id="cb13-24"><a href="#cb13-24" aria-hidden="true" tabindex="-1"></a>  extents exts0<span class="op">{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>;</span>
<span id="cb13-25"><a href="#cb13-25" aria-hidden="true" tabindex="-1"></a>  extents exts1<span class="op">{</span><span class="dv">3</span>, <span class="dv">4</span><span class="op">}</span>;</span>
<span id="cb13-26"><a href="#cb13-26" aria-hidden="true" tabindex="-1"></a>  extents exts2<span class="op">{</span><span class="dv">2</span>, <span class="dv">2</span><span class="op">}</span>;</span>
<span id="cb13-27"><a href="#cb13-27" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> y <span class="op">=</span> use_vector<span class="op">(</span>exts2, use_vector<span class="op">(</span>exts1, use_vector<span class="op">(</span>exts0, std<span class="op">::</span>move<span class="op">(</span>storage<span class="op">))))</span>;</span>
<span id="cb13-28"><a href="#cb13-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-29"><a href="#cb13-29" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;size of result of use_vector: &quot;</span> <span class="op">&lt;&lt;</span> y<span class="op">.</span>size<span class="op">()</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb13-30"><a href="#cb13-30" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>y<span class="op">.</span>size<span class="op">()</span> <span class="op">==</span> <span class="dv">12</span><span class="bu">u</span><span class="op">)</span>;</span>
<span id="cb13-31"><a href="#cb13-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-32"><a href="#cb13-32" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb13-33"><a href="#cb13-33" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="8" id="do-not-add-separate-constructors-from-flat-initializer-list"><span class="header-section-number">8</span> Do not add separate constructors
from “flat” initializer list<a href="#do-not-add-separate-constructors-from-flat-initializer-list" class="self-link"></a></h1>
<p>The previous section leads naturally to the discussion of
<code>initializer_list</code> constructors. A LEWG member, during LEWG’s
2023/11/09 review of P1684R5, asked whether we support use of
<code>initializer_list</code> in constructors to specify the
<code>mdarray</code>’s values. We presume that this means a flat
<code>initializer_list&lt;U&gt;</code> with <code>U</code> convertible
to <code>value_type</code>. Since this list is flat, the constructor
would need information about the extents and rank as well. If we ignore
CTAD, then the <code>mdarray</code> type would need all static extents,
like this.</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>mdarray<span class="op">&lt;</span><span class="dt">float</span>, extents<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">&gt;&gt;</span> m <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>  <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>,</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>  <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>With any dynamic extents, or with CTAD, the user would need to pass
in an extents or mapping object. It would make sense to put the values
in an <code>initializer_list</code>, in order to separate them from the
extents or mapping object.</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>mdarray m <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  dextents<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">2</span><span class="op">&gt;{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>,</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>,</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>    <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>The resulting constructors would look like this.</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">template</span><span class="op">&lt;</span> <span class="kw">class</span> U, <span class="kw">class</span><span class="op">...</span> Args <span class="op">&gt;</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>expected<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> exts,</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>initializer_list<span class="op">&lt;</span>value_type<span class="op">&gt;</span> il<span class="op">)</span>;</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span> <span class="kw">class</span> U, <span class="kw">class</span><span class="op">...</span> Args <span class="op">&gt;</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">explicit</span></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a>expected<span class="op">(</span><span class="kw">const</span> mapping_type<span class="op">&amp;</span> mapping,</span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>initializer_list<span class="op">&lt;</span>value_type<span class="op">&gt;</span> il<span class="op">)</span>;</span></code></pre></div>
<p>That looks almost the same as the <code>in_place_t</code>
constructors presented in the previous section. The only difference
would be semantic. Constructors taking <code>in_place_t</code> would
construct the container with the arguments – whatever that means for the
specific container type. For example, the arguments might include an
allocator. In contrast, the above non-<code>in_place_t</code>
constructors would fill the container with the values in the
<code>initializer_list</code>, for any container type. This would add to
the container type’s requirements, that forwarding the
<code>initializer_list</code> to the container would construct it with
those values. There are no existing named container requirements in the
Standard that would express this requirement; we would need to come up
with new wording. In contrast, the <code>in_place_t</code> constructors
would merely forward directly to the container’s constructor, and thus
would not impose any requirements intrinsically. On the other hand,
users would need to know what arguments make sense for the container
types they use.</p>
<p>If we only add the <code>in_place_t</code> constructors, that would
make CTAD use cases slightly more verbose, but it would make both the
wording and implementation easier.</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>mdarray m <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>,</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  in_place,</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>,</span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>    <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>There’s another concern here, which is that
<code>initializer_list</code>’s <code>size()</code> function can’t be
used in a deduction guide. Thus, with CTAD,
<code>initializer_list</code> construction would <em>necessarily</em>
result in <code>std::vector</code> being the container type, instead of
<code>std::array</code>. The user knows everything at compile time –
they have spelled out for us all the values with which to construct the
array! – but we would end up throwing that out, because of a limitation
of <code>initializer_list</code>. Now we’re calling <code>new</code> for
an array of 6 values that could very well be a compile-time
constant.</p>
<p>Contrast this with the current (R5) approach. The following example
takes four <em>fewer</em> characters than the <code>in_place</code>
example above, but it always uses <code>std::array</code>.</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>mdarray m <span class="op">{</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>,</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>  array<span class="op">{</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>,</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>    <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>What does this tell us?</p>
<ol type="1">
<li><p>Flat <code>initializer_list</code> plus CTAD is, surprisingly,
<em>not</em> a zero-overhead abstraction, because it forces use of the
default container <code>std::vector</code>.</p></li>
<li><p>Flat <code>initializer_list</code> <em>without</em> CTAD could be
a zero-overhead abstraction. However, this imposes an additional
requirement on the container type, which is both syntactic
(constructible from an <code>initializer_list</code>) and semantic
(construction from an <code>initializer_list</code> fills it with those
values in that order). We don’t have existing wording in the Standard to
reuse for this.</p></li>
<li><p>The <code>in_place_t</code> constructors cover both use cases.
They also impose fewer requirements on the container (or rather, they
push meeting those requirements to the user’s code). In addition, they
let users pass in arguments <em>other</em> than the initial values
(e.g., an allocator) to the container type’s constructor.</p></li>
</ol>
<p>We conclude that the <code>in_place_t</code> constructors are worth
adding, while separate non-<code>in_place_t</code>
<code>initializer_list</code> constructors would <em>not</em> be worth
adding.</p>
<h1 data-number="9" id="consider-adding-construction-from-nested-initializer-list"><span class="header-section-number">9</span> Consider adding construction from
nested initializer list<a href="#consider-adding-construction-from-nested-initializer-list" class="self-link"></a></h1>
<h2 data-number="9.1" id="why-we-want-this"><span class="header-section-number">9.1</span> Why we want this<a href="#why-we-want-this" class="self-link"></a></h2>
<p>It would be attractive if <code>mdarray</code> could take a nested
initializer list of values, and automatically deduce its (compile-time)
rank and (run-time) extents. For example, the following should deduce
the extents as <code>dims&lt;2&gt;</code>, that is,
<code>extents&lt;size_t, dynamic_extent, dynamic_extent&gt;</code>.</p>
<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>mdarray m_2d<span class="op">{</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span><span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span><span class="op">}</span>,</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span><span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span><span class="op">}</span></span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Deeper nesting can introduce rank-3 or even higher-rank
<code>mdarray</code>. This feature would make <code>mdarray</code>
construction look familiar to users of Matlab or Python, both popular
languages for machine learning and numerical computations. It’s
idiomatic for users of those languages to construct multidimensional
arrays with their values and extents all at once. Here’s a Matlab
construction of a rank-2 array with 3 rows and 4 columns,</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode matlab"><code class="sourceCode matlab"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="va">arr</span> <span class="op">=</span> [</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="fl">1</span><span class="op">,</span>  <span class="fl">2</span><span class="op">,</span>  <span class="fl">3</span><span class="op">,</span>  <span class="fl">4</span><span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="fl">5</span><span class="op">,</span>  <span class="fl">6</span><span class="op">,</span>  <span class="fl">7</span><span class="op">,</span>  <span class="fl">8</span><span class="op">;</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="fl">9</span><span class="op">,</span> <span class="fl">10</span><span class="op">,</span> <span class="fl">11</span><span class="op">,</span> <span class="fl">12</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
<p>and here’s the equivalent Python construction (using NumPy).</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>arr <span class="op">=</span> np.array([</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  [<span class="dv">1</span>,  <span class="dv">2</span>,  <span class="dv">3</span>,  <span class="dv">4</span>],</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  [<span class="dv">5</span>,  <span class="dv">6</span>,  <span class="dv">7</span>,  <span class="dv">8</span>],</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  [<span class="dv">9</span>, <span class="dv">10</span>, <span class="dv">11</span>, <span class="dv">12</span>]</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>])</span></code></pre></div>
<p>Users would want to construct a rank-2 <code>mdarray</code> in the
same way.</p>
<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>mdarray arr <span class="op">{</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span><span class="op">}</span>,</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span><span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>, <span class="dv">8</span><span class="op">}</span>,</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span><span class="dv">9</span>, <span class="dv">10</span>, <span class="dv">11</span>, <span class="dv">12</span><span class="op">}</span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<h2 data-number="9.2" id="limits-of-this-approach"><span class="header-section-number">9.2</span> Limits of this approach<a href="#limits-of-this-approach" class="self-link"></a></h2>
<ol type="1">
<li><p>The extents would need to be run-time values, since
<code>initializer_list</code> (unlike <code>array</code> or
<code>span</code>) doesn’t encode its <code>size()</code> in the type.
(That’s too bad, because the user has already told the compiler how long
each initializer list is!)</p></li>
<li><p>Nesting means that the implementation would need to traverse the
inner lists (to one less than the nesting level) to count the number of
elements, allocate the container with the count, and only then fill the
container by traversing the input again. This fills the container twice,
and requires that <code>value_type</code> be default
constructible.</p></li>
<li><p>The constructor would have a precondition that all the inner
lists at the same level would have the same size. (That precondition
could be checked at run time.)</p></li>
</ol>
<h2 data-number="9.3" id="alternative-make_mdarray-function"><span class="header-section-number">9.3</span> Alternative:
<code>make_mdarray</code> function<a href="#alternative-make_mdarray-function" class="self-link"></a></h2>
<p>As an alternative to CTAD and constructors, one could imagine a
<code>make_mdarray&lt;ValueType, Level&gt;</code> function template with
overloads for different levels of <code>initializer_list</code> nesting.
We would prefer CTAD, though, because it reduces the number of names to
remember. Users who want to be more explicit about types can always
spell out <code>mdarray</code>’s template arguments.</p>
<h2 data-number="9.4" id="implementation-approach"><span class="header-section-number">9.4</span> Implementation approach<a href="#implementation-approach" class="self-link"></a></h2>
<p>We can accomplish this with a single <code>mdarray</code>
constructor, by introducing a type alias (which in the wording would be
exposition only) to express nested <code>initializer_list</code> with a
known level of nesting.</p>
<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="kw">namespace</span> impl <span class="op">{</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, std<span class="op">::</span><span class="dt">size_t</span> Level<span class="op">&gt;</span></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> init_list <span class="op">{</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>Level <span class="op">!=</span> <span class="dv">0</span><span class="bu">u</span><span class="op">)</span>;  </span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> type <span class="op">=</span> std<span class="op">::</span>initializer_list<span class="op">&lt;</span><span class="kw">typename</span> init_list<span class="op">&lt;</span>T, Level <span class="op">-</span> <span class="dv">1</span><span class="bu">u</span><span class="op">&gt;::</span>type<span class="op">&gt;</span>;</span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-9"><a href="#cb23-9" 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="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> init_list<span class="op">&lt;</span>T, <span class="dv">0</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> type <span class="op">=</span> T;</span>
<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This would let <code>mdarray</code> have a constructor like the
following.</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>mdarray<span class="op">(</span><span class="kw">typename</span> init_list<span class="op">&lt;</span>value_type, extents_type<span class="op">::</span>rank<span class="op">()&gt;::</span>type values<span class="op">)</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span>Rank <span class="op">!=</span> <span class="dv">0</span><span class="op">)</span>;</span></code></pre></div>
<p>Here is a demo: https://godbolt.org/z/EKc3eaafb . The only issue is
that we would need a deduction guide for each level of nesting (and thus
for each rank), starting with 1 and going up to some
implementation-defined limit on the rank. <code>mdarray</code> could
still be constructed and used with higher rank, but CTAD from nested
<code>initializer_list</code> would not work for them. Here are the new
deduction guides we would need.</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> ValueType<span class="op">&gt;</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span><span class="kw">not</span> impl<span class="op">::</span>is_initializer_list_v<span class="op">&lt;</span>ValueType<span class="op">&gt;)</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>mdarray<span class="op">(</span>std<span class="op">::</span>initializer_list<span class="op">&lt;</span>ValueType<span class="op">&gt;)</span></span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">-&gt;</span> mdarray<span class="op">&lt;</span>ValueType, dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;&gt;</span>;</span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ValueType<span class="op">&gt;</span></span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span><span class="kw">not</span> impl<span class="op">::</span>is_initializer_list_v<span class="op">&lt;</span>ValueType<span class="op">&gt;)</span></span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a>mdarray<span class="op">(</span></span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>initializer_list<span class="op">&lt;</span></span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>initializer_list<span class="op">&lt;</span>ValueType<span class="op">&gt;</span></span>
<span id="cb25-11"><a href="#cb25-11" aria-hidden="true" tabindex="-1"></a>  <span class="op">&gt;)</span></span>
<span id="cb25-12"><a href="#cb25-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">-&gt;</span> mdarray<span class="op">&lt;</span>ValueType, dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;&gt;</span>;</span>
<span id="cb25-13"><a href="#cb25-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-14"><a href="#cb25-14" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ValueType<span class="op">&gt;</span></span>
<span id="cb25-15"><a href="#cb25-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span><span class="kw">not</span> impl<span class="op">::</span>is_initializer_list_v<span class="op">&lt;</span>ValueType<span class="op">&gt;)</span></span>
<span id="cb25-16"><a href="#cb25-16" aria-hidden="true" tabindex="-1"></a>mdarray<span class="op">(</span></span>
<span id="cb25-17"><a href="#cb25-17" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>initializer_list<span class="op">&lt;</span></span>
<span id="cb25-18"><a href="#cb25-18" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>initializer_list<span class="op">&lt;</span></span>
<span id="cb25-19"><a href="#cb25-19" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>initializer_list<span class="op">&lt;</span>ValueType<span class="op">&gt;</span></span>
<span id="cb25-20"><a href="#cb25-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">&gt;</span></span>
<span id="cb25-21"><a href="#cb25-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">&gt;)</span></span>
<span id="cb25-22"><a href="#cb25-22" aria-hidden="true" tabindex="-1"></a>  <span class="op">-&gt;</span> mdarray<span class="op">&lt;</span>ValueType, dims<span class="op">&lt;</span><span class="dv">3</span><span class="op">&gt;</span>;</span>
<span id="cb25-23"><a href="#cb25-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-24"><a href="#cb25-24" aria-hidden="true" tabindex="-1"></a><span class="co">// ... and so on, up to some implementation limit number of ranks</span></span></code></pre></div>
<p>As far as we know, there’s no generic way to define one (or a
constant number of) deduction guide(s) for all the levels of nesting. We
would welcome clever suggestions for fixing that.</p>
<p>This approach would only makes the notation more concise in the CTAD
case. If users must name the extents type anyway, then it’s an occasion
for error to specify the extents in two places – as the extents type
template argument, and implicitly in the lengths of the initializer
lists.</p>
<h1 data-number="10" id="add-an-executionpolicy-overload-to-construction-from-mdspan"><span class="header-section-number">10</span> Add an
<code>ExecutionPolicy&amp;&amp;</code> overload to construction from
<code>mdspan</code><a href="#add-an-executionpolicy-overload-to-construction-from-mdspan" class="self-link"></a></h1>
<p><code>mdarray</code> currently has a constructor from
<code>mdspan</code>, that deep-copies the elements of the
<code>mdspan</code>. This constructor is the only way for users to
construct an <code>mdarray</code> that is a deep copy of an arbitrary
<code>mdspan</code>. However, this constructor introduces a potential
performance problem. All the other constructors that copy the elements
of their input, copy the container directly. This can rely on whatever
optimizations the container has, including copying in parallel and/or
using an accelerator. The constructor from <code>mdspan</code> must
access the elements directly, in generic code. It has no way to deduce
the correct execution policy in order to make copying parallel, for
example. This has led to implementation divergence, for example in
NVIDIA’s RAPIDS RAFT library, which depends on the ability to use CUDA
streams to dispatch allocations and copying operations.</p>
<p>A natural fix would be to add a constructor with two parameters,
<code>ExecutionPolicy&amp;&amp;</code> and <code>mdspan</code>.</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> OtherElementType, <span class="kw">class</span> OtherExtents,</span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>         <span class="kw">class</span> OtherLayoutPolicy, <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span><span class="op">(</span><span class="co">/* see below */</span><span class="op">)</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mdarray<span class="op">(</span>ExecutionPolicy<span class="op">&amp;&amp;</span> policy,</span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> mdspan<span class="op">&lt;</span>OtherElementType, OtherExtents,</span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>      OtherLayoutPolicy, Accessor<span class="op">&gt;&amp;</span> other<span class="op">)</span>;</span></code></pre></div>
<p>While the Standard currently offers no generic way to use the
<code>ExecutionPolicy</code> for copying from an <code>mdspan</code>
into a container in parallel, this would at least offer a hook for
implementations to optimize inside the constructor. Users who call this
constructor would assert that it is correct to copy in parallel from the
input <code>mdspan</code> into the <code>mdarray</code>’s container.</p>
<p>P3240R0 (Copy and fill for <code>mdspan</code>) would provide a copy
algorithm with an <code>ExecutionPolicy&amp;&amp;</code> overload that
copies from the elements of a source <code>mdspan</code> to a
destination <code>mdspan</code>. This would let <code>mdarray</code>’s
wording (not just its implementation) specify how copying happens.
However, P3240R0 requires that all the elements of the destination of
the copy have started their lifetimes. For generic element types, this
would force <code>mdarray</code> to allocate and fill storage first,
before copying. For implicit-lifetime types (including all arithmetic
types – a common case for use of <code>mdarray</code>), a custom
container (not <code>std::vector</code>) could allocate without filling.
Then, <code>mdarray</code>’s constructor could copy from the input
<code>mdspan</code> to a temporary <code>mdspan</code> viewing its
container’s elements.</p>
<p>This leaves non-implicit-lifetime types pessimized. On the other
hand, adding <code>in_place_t</code> constructors to
<code>mdarray</code> means that if users have a custom container that
can be constructed directly from <code>mdspan</code> efficiently, then
that container would solve any performance issues resulting from
constructing an <code>mdarray</code> from an <code>mdspan</code>. That,
plus adding an <code>ExecutionPolicy&amp;&amp;</code>,
<code>mdspan</code> constructor to <code>mdarray</code>, should address
any performance issues.</p>
<h1 data-number="11" id="why-mdarray-is-a-container-adapter-and-not-a-container"><span class="header-section-number">11</span> Why <code>mdarray</code> is a
container adapter and not a container<a href="#why-mdarray-is-a-container-adapter-and-not-a-container" class="self-link"></a></h1>
<h2 data-number="11.1" id="consistency-with-mdspan"><span class="header-section-number">11.1</span> Consistency with
<code>mdspan</code><a href="#consistency-with-mdspan" class="self-link"></a></h2>
<p><code>mdarray</code> is a container adapter. It has a
<code>ContainerType</code> template parameter, stores an instance of
<code>ContainerType</code>, and returns references that it gets from the
container’s <code>operator[]</code> member function. The discussions in
the previous sections presume this design.</p>
<p>The main reason we chose this approach is for consistency with
<code>mdspan</code>. <code>mdspan</code> imposes multidimensional
behavior on a flat <em>view</em> of elements. Thus, by analogy,
<code>mdarray</code> should express multidimensional behavior on a flat
<em>container</em> of elements. That implies a container adapter design.
We could then say that “<code>mdspan</code> is a view adapter;
<code>mdarray</code> is a container adapter.” The R0 design reflected
this even more explicitly, with its <code>ContainerPolicy</code>
template parameter analogous to <code>mdspan</code>’s
<code>AccessorPolicy</code>.</p>
<p>In order to understand that design choice more fully, one should
entertain the alternative of making <code>mdarray</code> a container.
The discussion below explains what that design would look like, and its
advantages and disadvantages over the current container adapter
design.</p>
<h2 data-number="11.2" id="what-would-a-container-design-look-like"><span class="header-section-number">11.2</span> What would a container design
look like?<a href="#what-would-a-container-design-look-like" class="self-link"></a></h2>
<p>A container design with the same functionality as
<code>mdarray</code> in P1684R5 would actually need two containers,
which we provisionally call <code>md_fixed_array</code> and
<code>md_dynamic_array</code>.</p>
<ol type="1">
<li><p><code>md_fixed_array</code></p>
<ul>
<li>Stores all elements as if in a <code>std::array</code></li>
<li>Requires that all the extents be static</li>
<li>Move behavior is like that of <code>std::array</code></li>
</ul></li>
<li><p><code>md_dynamic_array</code></p>
<ul>
<li>Stores all elements as if in a dynamically allocated container, like
<code>std::vector</code> (but without resizing)</li>
<li>Permits any combination of dynamic or static extents (including all
static extents)</li>
<li>Move behavior is like that of <code>std::vector</code>: constant
time, does not copy the elements, and leaves the moved-from container
empty; the moved-from container’s elements can no longer be
accessed</li>
<li>Has all the allocator-aware machinery of
<code>std::vector</code></li>
</ul></li>
</ol>
<h2 data-number="11.3" id="advantages-of-a-container-design"><span class="header-section-number">11.3</span> Advantages of a container
design<a href="#advantages-of-a-container-design" class="self-link"></a></h2>
<ol type="1">
<li><p>It would solve the problem of defining the moved-from state of
<code>mdarray</code>, since we could define it ourselves.</p></li>
<li><p><code>mdarray</code> exists entirely to make <code>mdspan</code>
easier to use for common cases. We expect that most users would not use
custom container types with <code>mdarray</code>, for example.</p></li>
<li><p><code>mdarray</code> needs preconditions for corner cases, such
as having one or more dynamic extents, but with <code>array</code> as
its container type. <code>md_fixed_array</code> and
<code>md_dynamic_array</code> would not need this. (Note that in
previous P1684 reviews, LEWG explicitly rejected our proposal to make
<code>mdarray</code>’s default container type <code>array</code> if all
the extents are static, and <code>vector</code> otherwise.)</p></li>
<li><p>Separating the <code>md_fixed_array</code> and
<code>md_dynamic_array</code> cases would simplify wording for
each.</p></li>
<li><p>The existing Container requirements in the Standard do not cover
what <code>mdarray</code> needs. <code>mdarray</code> thus finds itself
forging new wording ground. This would be in a part of the Standard –
container requirements – about which we have heard WG21 members express
concerns: for example, that it’s old, that it scatters requirements in
many different places (making it hard to maintain), and that it is not
as consistent as we wish it could be.</p></li>
<li><p>The most reasonable default container type for a container
adapter is <code>vector</code>. However, this is not a zero-overhead
abstraction, as <code>vector</code> stores a capacity in order to
support efficient resizing, but <code>mdarray</code> cannot be resized
and thus does not need the capacity. The Standard does not have a
container type like that.</p></li>
</ol>
<p>Regarding the default container type for <code>mdarray</code>, one
might think of <code>dynarray</code>.
(<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3662.html">N3662
(“C++ Dynamic Arrays”)</a> proposed <code>dynarray</code>. It was later
voted out of C++14 into a Technical Specification.) However,
<code>dynarray</code> is not quite the container needed here. It does
not have move construction at all, and thus cannot promise anything
about the cost or postconditions of moves.</p>
<h2 data-number="11.4" id="disadvantages-of-a-container-design"><span class="header-section-number">11.4</span> Disadvantages of a container
design<a href="#disadvantages-of-a-container-design" class="self-link"></a></h2>
<ol type="1">
<li><p>The Standard Library’s container requirements all include
iterators. For <code>mdarray</code>-like container classes, this would
require us to define iterators. We deliberately did not define iterators
for <code>mdspan</code>, because they are nearly impossible to make
performant without fanciful compiler support.</p></li>
<li><p>The container approach would not solve the problem of how to
define the behavior of a moved-from object. Consider
<code>md_dynamic_array</code>. It’s tempting to set its dynamic extents
to zero after moving from the object, so that the moved-from object has
zero elements. However, any static extents could not be changed. If the
object has all static extents, it would still have a nonzero number of
elements. It would also be confusing for an
<code>md_dynamic_array</code> object with dynamic extents to behave
differently at run time than an <code>md_dynamic_array</code> object
with static extents.</p></li>
<li><p>The container adapter approach gives users a hook to specify how
copying elements happens in parallel (with the exception of assignment
from <code>mdspan</code>; see section below). For example, a custom
container might have an accelerator-specific resource (e.g., a CUDA
stream) in it that would be used for copies. The container approach
would make this impossible to specify in a generic way; users would have
no place other than a custom allocator to store parallel execution
information, but generic C++ code wouldn’t have a way to get that
information out and pass it into <code>std::copy</code> (for
example).</p></li>
<li><p>Specifying a new container type is complicated. We would find
ourselves replicating a lot of <code>vector</code>’s wording. As a
result, total wording length could actually increase. This would also
impose future costs if WG21 later wants to revise <code>vector</code>’s
wording.</p></li>
<li><p>Construction from <code>container_type&amp;&amp;</code> and the
member function
<code>container_type&amp;&amp; extract_container()</code> support a
specific use case: representing dynamically allocated storage as a
container and “passing it along” a chain of operations. Changing from a
container adapter to a container would make this use case harder. Users
would need to create an allocator, instead of just creating a
<code>vector</code> and passing it along.</p></li>
</ol>
<h2 data-number="11.5" id="no-major-notational-advantages"><span class="header-section-number">11.5</span> No major notational
advantages<a href="#no-major-notational-advantages" class="self-link"></a></h2>
<p>All this being said, though, the container approach offers no major
notational advantages for users over the container adapter approach. For
example, the P1684R5 container adapter design permits the following CTAD
construction.</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a>mdarray m <span class="op">{</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>,</span>
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a>  array<span class="op">{</span></span>
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>,</span>
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a>    <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span></span>
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>The natural analog with <code>md_fixed_array</code> would be an
<code>initializer_list&lt;value_type&gt;</code> constructor (without
<code>in_place_t</code>, which would only make sense for a container
adapter).</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>mdarray_fixed_array m <span class="op">{</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">{</span><span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>,</span>
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, <span class="fl">2.0</span><span class="bu">f</span>, <span class="fl">3.0</span><span class="bu">f</span>,</span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a>    <span class="fl">4.0</span><span class="bu">f</span>, <span class="fl">5.0</span><span class="bu">f</span>, <span class="fl">6.0</span><span class="bu">f</span></span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</div>
</div>
</body>
</html>
