<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2024-08-04" />
  <title>aligned_accessor: An mdspan accessor expressing pointer overalignment</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>aligned_accessor</code>:
An mdspan accessor expressing pointer overalignment</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #: </td>
    <td>P2897R5</td>
  </tr>
  <tr>
    <td>Date: </td>
    <td>2024-08-04</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>
      Damien Lebrun-Grandie<br>&lt;<a href="mailto:lebrungrandt@ornl.gov" class="email">lebrungrandt@ornl.gov</a>&gt;<br>
      Nicolas Morales<br>&lt;<a href="mailto:nmmoral@sandia.gov" class="email">nmmoral@sandia.gov</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="#purpose-of-this-paper" id="toc-purpose-of-this-paper"><span class="toc-section-number">3</span>
Purpose of this paper</a></li>
<li><a href="#key-features" id="toc-key-features"><span class="toc-section-number">4</span> Key features</a></li>
<li><a href="#design-discussion" id="toc-design-discussion"><span class="toc-section-number">5</span> Design discussion</a>
<ul>
<li><a href="#the-accessor-is-not-nestable" id="toc-the-accessor-is-not-nestable"><span class="toc-section-number">5.1</span> The accessor is not
nestable</a></li>
<li><a href="#explicit-constructor-from-default_accessor" id="toc-explicit-constructor-from-default_accessor"><span class="toc-section-number">5.2</span> Explicit constructor from
<code>default_accessor</code></a></li>
<li><a href="#why-no-explicit-constructor-from-less-to-more-alignment" id="toc-why-no-explicit-constructor-from-less-to-more-alignment"><span class="toc-section-number">5.3</span> Why no explicit constructor from
less to more alignment?</a></li>
<li><a href="#we-do-not-define-an-alias-for-aligned-mdspan" id="toc-we-do-not-define-an-alias-for-aligned-mdspan"><span class="toc-section-number">5.4</span> We do not define an alias for
aligned mdspan</a></li>
<li><a href="#mdspan-construction-safety" id="toc-mdspan-construction-safety"><span class="toc-section-number">5.5</span> mdspan construction
safety</a></li>
<li><a href="#is_sufficiently_aligned-is-not-constexpr" id="toc-is_sufficiently_aligned-is-not-constexpr"><span class="toc-section-number">5.6</span>
<code>is_sufficiently_aligned</code> is not
<code>constexpr</code></a></li>
<li><a href="#generalize-is_sufficiently_aligned-for-all-accessors" id="toc-generalize-is_sufficiently_aligned-for-all-accessors"><span class="toc-section-number">5.7</span> Generalize
<code>is_sufficiently_aligned</code> for all accessors?</a>
<ul>
<li><a href="#detectably_invalid-generic-validity-check" id="toc-detectably_invalid-generic-validity-check"><span class="toc-section-number">5.7.1</span> <code>detectably_invalid</code>:
Generic validity check?</a></li>
<li><a href="#arguments-against-and-for-detectably_invalid" id="toc-arguments-against-and-for-detectably_invalid"><span class="toc-section-number">5.7.2</span> Arguments against and for
<code>detectably_invalid</code></a></li>
<li><a href="#users-could-work-around-the-breaking-change-of-adding-detectably_invalid-to-accessor-requirements" id="toc-users-could-work-around-the-breaking-change-of-adding-detectably_invalid-to-accessor-requirements"><span class="toc-section-number">5.7.3</span> Users could work around the
breaking change of adding <code>detectably_invalid</code> to accessor
requirements</a></li>
<li><a href="#is_sufficiently_aligned-is-still-useful-on-its-own" id="toc-is_sufficiently_aligned-is-still-useful-on-its-own"><span class="toc-section-number">5.7.4</span>
<code>is_sufficiently_aligned</code> is still useful on its own</a></li>
<li><a href="#nonmember-is_sufficiently_aligned" id="toc-nonmember-is_sufficiently_aligned"><span class="toc-section-number">5.7.5</span> Nonmember
<code>is_sufficiently_aligned</code></a></li>
<li><a href="#do-accessors-need-to-check-anything-else" id="toc-do-accessors-need-to-check-anything-else"><span class="toc-section-number">5.7.6</span> Do accessors need to check
anything else?</a></li>
<li><a href="#naming-the-function" id="toc-naming-the-function"><span class="toc-section-number">5.7.7</span> Naming the function</a></li>
<li><a href="#conclusions" id="toc-conclusions"><span class="toc-section-number">5.7.8</span> Conclusions</a></li>
</ul></li>
<li><a href="#explicit-conversions-as-the-model-for-precondition-asserting-conversions" id="toc-explicit-conversions-as-the-model-for-precondition-asserting-conversions"><span class="toc-section-number">5.8</span> Explicit conversions as the model
for precondition-asserting conversions</a>
<ul>
<li><a href="#example-conversion-to-aligned_accessor" id="toc-example-conversion-to-aligned_accessor"><span class="toc-section-number">5.8.1</span> Example: conversion to
<code>aligned_accessor</code></a></li>
<li><a href="#status-quo" id="toc-status-quo"><span class="toc-section-number">5.8.2</span> Status quo</a></li>
<li><a href="#mdspan-uses-explicit-conversions-to-assert-preconditions" id="toc-mdspan-uses-explicit-conversions-to-assert-preconditions"><span class="toc-section-number">5.8.3</span> <code>mdspan</code> uses
explicit conversions to assert preconditions</a></li>
<li><a href="#alternative-explicit-cast-function-naughty_cast" id="toc-alternative-explicit-cast-function-naughty_cast"><span class="toc-section-number">5.8.4</span> Alternative: explicit cast
function <code>naughty_cast</code></a></li>
<li><a href="#conclusion-retain-mdspans-current-design" id="toc-conclusion-retain-mdspans-current-design"><span class="toc-section-number">5.8.5</span> Conclusion: retain
<code>mdspan</code>’s current design</a></li>
</ul></li>
</ul></li>
<li><a href="#implementation" id="toc-implementation"><span class="toc-section-number">6</span> Implementation</a></li>
<li><a href="#example" id="toc-example"><span class="toc-section-number">7</span> Example</a></li>
<li><a href="#references" id="toc-references"><span class="toc-section-number">8</span> References</a></li>
<li><a href="#acknowledgments" id="toc-acknowledgments"><span class="toc-section-number">9</span> Acknowledgments</a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">10</span> Wording</a>
<ul>
<li><a href="#add-aligned_accessor-declaration-to-mdspan-header-synopsis" id="toc-add-aligned_accessor-declaration-to-mdspan-header-synopsis"><span class="toc-section-number">10.1</span> Add <code>aligned_accessor</code>
declaration to <code>&lt;mdspan&gt;</code> header synopsis</a></li>
<li><a href="#add-subsection-mdspan.accessor.aligned-with-the-following" id="toc-add-subsection-mdspan.accessor.aligned-with-the-following"><span class="toc-section-number">10.2</span> Add subsection �
[mdspan.accessor.aligned] with the following</a></li>
<li><a href="#members-mdspan.accessor.aligned.members" id="toc-members-mdspan.accessor.aligned.members"><span class="toc-section-number">10.3</span> Members
[mdspan.accessor.aligned.members]</a></li>
</ul></li>
<li><a href="#appendix-a-detectably_invalid-nonmember-function-example" id="toc-appendix-a-detectably_invalid-nonmember-function-example"><span class="toc-section-number">11</span> Appendix A:
<code>detectably_invalid</code> nonmember function example</a></li>
<li><a href="#appendix-b-implementation-and-demo" id="toc-appendix-b-implementation-and-demo"><span class="toc-section-number">12</span> Appendix B: Implementation and
demo</a></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>Damien Lebrun-Grandie (lebrungrandt@ornl.gov) (Oak Ridge National
Laboratory)</p></li>
<li><p>Nicolas Morales (nmmoral@sandia.gov) (Sandia National
Laboratories)</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><p>Revision 0 (pre-Varna) to be submitted 2023-05-19</p></li>
<li><p>Revision 1 (pre-Kona) to be submitted 2023-10-15</p>
<ul>
<li><p>Implement changes requested by LEWG review on 2023-10-10</p>
<ul>
<li><p>Change <code>gcd</code> converting constructor Constraint to a
Mandate</p></li>
<li><p>Add Example in the wording section that uses
<code>is_sufficiently_aligned</code> to check the pointer overalignment
precondition</p></li>
<li><p>Add Example in the wording section that uses
<code>aligned_alloc</code> to create an overaligned allocation, to show
that <code>aligned_accessor</code> exists as part of a system</p></li>
<li><p>Add an <code>explicit</code> constructor from default_accessor,
so that users can type <code>aligned_mdspan y{x}</code> instead of
<code>aligned_mdspan y{x.data_handle(), x.mapping()}</code>. Add an
explanation in the design discussion section.</p></li>
</ul></li>
<li><p>Implement other wording changes</p>
<ul>
<li>Add to <code>aligned_accessor</code>’s Mandates that
<code>byte_alignment &gt;= alignof(ElementType)</code> is
<code>true</code>. This prevents construction of an invalid
<code>aligned_accessor</code> object.</li>
</ul></li>
<li><p>Add more design discussion based on LEWG review on 2023-10-10</p>
<ul>
<li><p>Explain why we do not include an <code>aligned_mdspan</code>
alias</p></li>
<li><p>Explain <code>aligned_accessor</code> construction
safety</p></li>
</ul></li>
</ul></li>
<li><p>Revision 2 (post - St. Louis) to be submitted 2024-07-15</p>
<ul>
<li><p>Implement required changes from LEWG review of R1 on
2024-06-28</p>
<ul>
<li>Remove <code>constexpr</code> from
<code>is_sufficiently_aligned</code></li>
</ul></li>
<li><p>Discuss optional suggestions from LEWG review of R1 on
2024-06-28</p>
<ul>
<li><p>Add <code>explicit</code> converting constructor vs. named cast
(“<code>naughty_cast</code>”) discussion</p></li>
<li><p>Add <code>detectably_invalid</code> discussion</p></li>
<li><p>Ask LEWG to consider the alternative design that makes
<code>is_sufficiently_aligned</code> a nonmember function in
<code>&lt;bit&gt;</code> instead of a member function of
<code>aligned_accessor</code>, while LWG review of R2 proceeds
concurrently</p></li>
</ul></li>
<li><p>P2389R2 was voted into the Working Draft at St. Louis, so replace
use of <code>dextents</code> in examples with
<code>dims</code>.</p></li>
<li><p>Add non-wording section explaining why
<code>aligned_accessor</code> has no <code>explicit</code> constructor
from less to more alignment</p></li>
<li><p>Add Compiler Explorer link with full implementation and
demo</p></li>
</ul></li>
<li><p>Revision 3 (post - St. Louis) to be submitted 2024-07-15</p>
<ul>
<li>Include updated feedback from David Sankel (see Acknowledgments)
after his review of R2</li>
</ul></li>
<li><p>Revision 4 (post - St. Louis) to be submitted 2024-07-24</p>
<ul>
<li>Make <code>is_sufficiently_aligned</code> a nonmember function
instead of a static member function of <code>aligned_accessor</code>. R3
presented this only as an alternative. R4 makes this the actually
proposed design.</li>
</ul></li>
<li><p>Revision 5 (post - St. Louis) to be submitted by 2024-08-15</p>
<ul>
<li><p>Move <code>is_sufficiently_aligned</code> from
<code>&lt;bit&gt;</code> to <code>&lt;memory&gt;</code>, due to feedback
from LEWG mailing list review of R4</p></li>
<li><p>Give <code>is_sufficiently_aligned</code> a “<em>Throws</em>:
Nothing” clause and add nonwording text explaining why</p></li>
</ul></li>
</ul>
<h1 data-number="3" id="purpose-of-this-paper"><span class="header-section-number">3</span> Purpose of this paper<a href="#purpose-of-this-paper" class="self-link"></a></h1>
<p>We propose adding <code>aligned_accessor</code> to the C++ Standard
Library. This class template is an <code>mdspan</code> accessor policy
that uses <code>assume_aligned</code> to decorate pointer access. We
think it belongs in the Standard Library for two reasons. First, it
would serve as a common vocabulary type for interfaces that take
<code>mdspan</code> to declare their minimum alignment requirements.
Second, it extends to <code>mdspan</code> accesses the optimizations
that compilers can perform to pointers decorated with
<code>assume_aligned</code>.</p>
<p><code>aligned_accessor</code> is analogous to the various
<code>atomic_accessor_*</code> templates proposed by P2689. Both that
proposal and this one start with a Standard Library feature that
operates on a “raw” pointer (<code>assume_aligned</code> or the various
<code>atomic_ref*</code> templates), and then propose an
<code>mdspan</code> accessor policy that straightforwardly wraps the
lower-level feature.</p>
<p>We had originally written <code>aligned_accessor</code> as an example
in P2642, which proposes “padded” mdspan layouts. We realized that
<code>aligned_accessor</code> was more generally applicable and that
standardization would help the padded layouts proposed by P2642 reach
their maximum value.</p>
<h1 data-number="4" id="key-features"><span class="header-section-number">4</span> Key features<a href="#key-features" class="self-link"></a></h1>
<ul>
<li><p><code>offset_policy</code> is
<code>default_accessor</code></p></li>
<li><p><code>data_handle_type</code> is
<code>ElementType*</code></p></li>
<li><p>Permitted implicit conversions</p>
<ul>
<li><p>from nonconst to const <code>ElementType</code>,</p></li>
<li><p>from more overalignment to less overalignment, and</p></li>
<li><p>from overalignment to no overalignment
(<code>default_accessor</code>)</p></li>
</ul></li>
<li><p><code>explicit</code> converting constructor from
<code>default_accessor</code> lets users assert overalignment</p></li>
<li><p>New nonmember function <code>is_sufficiently_aligned</code> lets
users check a pointer’s alignment before using it with
<code>aligned_accessor</code></p></li>
</ul>
<p>The <code>offset_policy</code> alias is
<code>default_accessor&lt;ElementType&gt;</code>, because even if a
pointer <code>p</code> is aligned, <code>p + i</code> might not be.</p>
<p>The <code>data_handle_type</code> alias is <code>ElementType*</code>.
It needs no further adornment, because alignment is asserted at the
point of access, namely in the <code>access</code> function. Some
implementations might have an easier time optimizing if they also apply
some implementation-specific attribute to <code>data_handle_type</code>
itself. Examples of such attributes include
<code>__declspec(align_value(byte_alignment))</code> and
<code>__attribute__((align_value(byte_alignment)))</code>. However,
these attributes should not apply to the result of <code>offset</code>,
for the same reason that <code>offset_policy</code> is
<code>default_accessor</code> and not <code>aligned_accessor</code>.</p>
<p>The converting constructor from <code>aligned_accessor</code> is
analogous to <code>default_accessor</code>’s constructor, in that it
exists to permit conversion from nonconst <code>element_type</code> to
const <code>element_type</code>. It additionally permits implicit
conversion from more overalignment to less overalignment – something
that we expect users may need to do. For example, users may start with
<code>aligned_accessor&lt;float, 128&gt;</code>, because their
allocation function promises 128-byte alignment. However, they may then
need to call a function that takes an <code>mdspan</code> with
<code>aligned_accessor&lt;float, 32&gt;</code>, which declares the
function’s intent to use 8-wide SIMD of <code>float</code>.</p>
<p>The <code>explicit</code> converting constructor from
<code>default_accessor</code> lets users assert that an
<code>mdspan</code>’s pointer is overaligned. This follows the idiom of
existing <code>mdspan</code> layout mappings and accessors, where all
conversions with preconditions are expressed as <code>explicit</code>
constructors or conversion operators.</p>
<p>We do <em>not</em> provide an <code>explicit</code> conversion from
an <code>aligned_accessor</code> with less alignment to an
<code>aligned_accessor</code> with more alignment. As we explain below,
we think that if users need to do this conversion very often, then they
likely have a design problem.</p>
<p>The <code>is_sufficiently_aligned</code> function checks whether a
pointer has sufficient alignment to be used correctly with the class.
This makes it easier for users to check preconditions, without needing
to know how to cast a pointer to an integer of the correct size and
signedness. As of R4 of this proposal, this is no longer a static member
function of <code>aligned_accessor</code>. Instead, it is a nonmember
function in the <code>&lt;memory&gt;</code> header.</p>
<h1 data-number="5" id="design-discussion"><span class="header-section-number">5</span> Design discussion<a href="#design-discussion" class="self-link"></a></h1>
<h2 data-number="5.1" id="the-accessor-is-not-nestable"><span class="header-section-number">5.1</span> The accessor is not nestable<a href="#the-accessor-is-not-nestable" class="self-link"></a></h2>
<p>We considered making <code>aligned_accessor</code> “wrap” any
accessor type that meets the right requirements. For example,
<code>aligned_accessor</code> could take the inner accessor as a
template parameter, store an instance of it, and dispatch to its member
functions. That would give users a way to apply multiple accessor
“attributes” to their data handle, such as atomic access (see P2689) and
overalignment.</p>
<p>We decided against this approach for three reasons. First, we would
have no way to validate that the user’s accessor type has the correct
behavior. We could check that their accessor’s
<code>data_handle_type</code> is a pointer type, but we could not check
that their accessor’s <code>access</code> function actually dereferences
the pointer. For instance, <code>access</code> might instead interpret
the pointer as a file handle or a key into a distributed data store.</p>
<p>Second, even if the inner accessor’s <code>access</code> function
actually did return the result of dereferencing the pointer, the outer
<code>access</code> function might not be able to recover the effects of
the inner <code>access</code> function, because <code>access</code>
computes a <code>reference</code>, not a pointer. In order for
<code>aligned_accessor</code>’s <code>access</code> function to get back
that pointer, it would need to reach past the inner accessor’s public
interface. That would defeat the purpose of generic nesting.</p>
<p>Third, any way (not just this one) of nesting two generic accessors
raises the question of order dependence. Even if it were possible to
apply the effects of both the inner and outer accessors’
<code>access</code> functions in sequence, it might be unpleasantly
surprising to users if the effects depended on the order of nesting. A
similar question came up in the “properties” proposal P0900, which we
quote here.</p>
<blockquote>
<p>Practically speaking, it would be considered a best practice of a
high-quality implementation to ensure that a property’s implementation
of <code>properties::element_type_t</code> (and other traits) are
invariant with respect to ordering with other known properties (such as
those in the standard library), but with this approach it would be
impossible to make that guarantee formal, particularly with respect to
other vendor-defined and user-defined properties unknown to the property
implementer.</p>
</blockquote>
<p>For these reasons, we have made <code>aligned_accessor</code>
stand-alone, instead of having it modify another user-provided
accessor.</p>
<h2 data-number="5.2" id="explicit-constructor-from-default_accessor"><span class="header-section-number">5.2</span> Explicit constructor from
<code>default_accessor</code><a href="#explicit-constructor-from-default_accessor" class="self-link"></a></h2>
<p>LEWG’s 2023-10-10 review of R0 pointed out that in R0,
<code>aligned_accessor</code> lacks an <code>explicit</code> constructor
from <code>default_accessor</code>. Having that constructor would make
it easier for users to create an aligned <code>mdspan</code> from an
unaligned <code>mdspan</code>. Making it <code>explicit</code> would
prevent implicit conversion. Thus, we have decided to add this
<code>explicit</code> constructor in R1.</p>
<p>Without the <code>explicit</code> constructor, users have two options
for turning a nonaligned <code>mdspan</code> into an aligned
<code>mdspan</code>. First, as in the following example, users could
“take apart” the input nonaligned <code>mdspan</code> and use the pieces
to construct an aligned <code>mdspan</code>, whose type they name
completely.</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="dt">void</span> compute_with_aligned<span class="op">(</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span> matrix<span class="op">)</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> byte_alignment <span class="op">=</span> <span class="dv">4</span> <span class="op">*</span> <span class="kw">alignof</span><span class="op">(</span><span class="dt">float</span><span class="op">)</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> aligned_matrix_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>,</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>layout_left, std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  aligned_matrix_t aligned_matrix<span class="op">{</span>matrix<span class="op">.</span>data_handle<span class="op">()</span>, matrix<span class="op">.</span>mapping<span class="op">()}</span>;</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... use aligned_matrix ...</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Second, as in the following example, users could construct an
<code>aligned_accessor</code> explicitly and use constructor template
argument deduction (CTAD) to construct the aligned <code>mdspan</code>
from its pieces.</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="dt">void</span> compute_with_aligned<span class="op">(</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span> matrix<span class="op">)</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> byte_alignment <span class="op">=</span> <span class="dv">4</span> <span class="op">*</span> <span class="kw">alignof</span><span class="op">(</span><span class="dt">float</span><span class="op">)</span>;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan aligned_matrix<span class="op">{</span>matrix<span class="op">.</span>data_handle<span class="op">()</span>, matrix<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;{}}</span>;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... use aligned_matrix ...</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The first approach would likely be more common. This is because
<code>mdspan</code> users commonly define their own type aliases for
<code>mdspan</code>, with application-specific names that make code more
self-documenting. The <code>aligned_matrix_t</code> definition above is
an an example.</p>
<p>Adding an <code>explicit</code> constructor from
<code>default_accessor</code> lets users get the same effect more
concisely, without needing to “take apart” the input
<code>mdspan</code>.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> compute_with_aligned<span class="op">(</span>std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span>, <span class="dt">int</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span> matrix<span class="op">)</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> byte_alignment <span class="op">=</span> <span class="dv">4</span> <span class="op">*</span> <span class="kw">alignof</span><span class="op">(</span><span class="dt">float</span><span class="op">)</span>;</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> aligned_mdspan <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span>, <span class="dt">int</span><span class="op">&gt;</span>,</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>layout_left, std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan aligned_matrix<span class="op">{</span>matrix<span class="op">}</span>;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... use aligned_matrix ...</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The <code>explicit</code> constructor does not decrease safety, in
the sense that users were always allowed to convert from an
<code>mdspan</code> with <code>default_accessor</code> to an
<code>mdspan</code> with <code>aligned_accessor</code>. Before, users
could perform this conversion by typing the following.</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>aligned_matrix_t aligned_matrix<span class="op">{</span>matrix<span class="op">.</span>data_handle<span class="op">()</span>, matrix<span class="op">.</span>mapping<span class="op">()}</span>;</span></code></pre></div>
<p>Now, users can do the same thing with fewer characters.</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>aligned_matrix_t aligned_matrix<span class="op">{</span>matrix<span class="op">}</span>;</span></code></pre></div>
<h2 data-number="5.3" id="why-no-explicit-constructor-from-less-to-more-alignment"><span class="header-section-number">5.3</span> Why no explicit constructor
from less to more alignment?<a href="#why-no-explicit-constructor-from-less-to-more-alignment" class="self-link"></a></h2>
<p>As explained in the previous section, <code>aligned_accessor</code>
has an <code>explicit</code> converting constructor from
<code>default_accessor</code> so that users can assert overalignment. It
also has an (implicit) converting constructor from another
<code>aligned_accessor</code> with more alignment, to an
<code>aligned_accessor</code> with less alignment. However,
<code>aligned_accessor</code> does <em>not</em> have an
<code>explicit</code> converting constructor from another
<code>aligned_accessor</code> with <em>less</em> alignment, to an
<code>aligned_accessor</code> with <em>more</em> alignment. Why not?</p>
<p>Consider the three typical use cases for
<code>aligned_accessor</code>.</p>
<ol type="1">
<li><p>User knows an allocation’s alignment at compile time.</p></li>
<li><p>User knows an allocation’s alignment at run time, but not at
compile time. For example, the value might depend on run-time detection
of particular hardware features.</p></li>
<li><p>User doesn’t know whether an allocation is overaligned. They
might need to ask some system at run time, or check the pointer value
themselves, in order to decide whether to call code that expects a
particular alignment.</p></li>
</ol>
<p>In Case (1), users would normally declare the maximum alignment. They
would want to preserve this information at compile time as much as
possible, by keeping the <code>aligned_accessor</code>
<code>mdspan</code> with maximum compile-time alignment for the entire
scope of its use. Users would only want implicit conversions to less
alignment or <code>default_accessor</code> when calling functions whose
parameter types encode these requirements.</p>
<p>Case (2) reduces to Case (3).</p>
<p>Case (3) reduces to Case (1). This works like any conversion from
run-time type to compile-time type, with a fixed list of possible
compile-time types (the alignments). As soon as a user’s
<code>mdspan</code> enters a scope where the alignment is known at
compile time, the user would want to preserve that compile-time
information and maximize the alignment for as large of a scope as
possible.</p>
<p>None of these cases involve starting with more alignment, going to
less (but still some) alignment, and then going back to more alignment
again. Code that does that probably does not correctly use the types of
function parameters to express its overalignment requirements. It’s like
code that uses <code>dynamic_cast</code> a lot. Users can still convert
from less or more alignment by creating the result’s
<code>aligned_accessor</code> manually. However, we don’t want to
encourage this pattern, so we don’t offer an explicit conversion for
it.</p>
<h2 data-number="5.4" id="we-do-not-define-an-alias-for-aligned-mdspan"><span class="header-section-number">5.4</span> We do not define an alias for
aligned mdspan<a href="#we-do-not-define-an-alias-for-aligned-mdspan" class="self-link"></a></h2>
<p>In LEWG’s 2023-10-10 review of R0, participants observed that this
proposal’s examples define an example-specific type alias for
<code>mdspan</code> with <code>aligned_accessor</code>. They asked
whether our proposal should include a <em>standard</em> alias
<code>aligned_mdspan</code>. We do not <em>object</em> to such an alias,
but we do not find it very useful, for the following reasons.</p>
<ol type="1">
<li><p>Users of <code>mdspan</code> commonly define their own type
aliases whose names are meaningful for their applications.</p></li>
<li><p>It would not save much typing.</p></li>
</ol>
<p>Examples may define aliases to make them more concise. One example in
this proposal defines the following alias for an <code>mdspan</code> of
<code>float</code> with alignment <code>byte_alignment</code>.</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="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span>, <span class="dt">int</span><span class="op">&gt;</span>,</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>layout_right, std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>This lets the example use <code>aligned_mdspan&lt;32&gt;</code> and
<code>aligned_mdspan&lt;16&gt;</code>.</p>
<p>The above alias is specific to a particular example. A
<em>general</em> version of alias would look like this.</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> ElementType, <span class="kw">class</span> Extents, <span class="kw">class</span> Layout,</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType, Extents, Layout,</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span>ElementType, byte_alignment<span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>This alias would save <em>some</em> typing. However, mdspan “power
users” rarely type out all the template arguments. First, they can rely
on CTAD to create <code>mdspan</code>s, and <code>auto</code> to return
them. Second, users commonly already define their own aliases whose
names have an application-specific meaning. They define these aliases
<em>once</em> and use them throughout the application. For instance,
users might define the following.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> vector_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType,</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span>;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> matrix_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType,</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span>;</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_vector_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType,</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left, </span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span>ElementType, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_matrix_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType,</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left, </span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span>ElementType, byte_alignment<span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>Such users may never type the characters “<code>mdspan</code>” again.
For this reason, while we do not object to an
<code>aligned_mdspan</code> alias, we do not find the proliferation of
aliases particularly ergonomic.</p>
<h2 data-number="5.5" id="mdspan-construction-safety"><span class="header-section-number">5.5</span> mdspan construction safety<a href="#mdspan-construction-safety" class="self-link"></a></h2>
<p>LEWG’s 2023-10-10 review of R0 expressed concern that
<code>mdspan</code>’s constructor has no way to check
<code>aligned_accessor</code>’s alignment requirements. Users can call
<code>is_sufficiently_aligned</code> to check the pointer before
constructing the <code>mdspan</code> with it. However,
<code>mdspan</code>’s constructor generally has no way to check whether
its accessor finds the caller’s data handle acceptable.</p>
<p>This is true for any accessor type, not just for
<code>aligned_accessor</code>. It is a design feature of
<code>mdspan</code> that accessors can be stateless. Most of them have
no state. Even if they have state, they generally do not store the data
handle (as that would be redundant with the <code>mdspan</code>) and are
thus generally not constructed with the data handle. As a result, an
accessor might not see a data handle until <code>access</code> or
<code>offset</code> is called. Both of those member functions are
performance critical, so they cannot afford an extra branch on every
call. Compare to <code>vector::operator[]</code>, which has
preconditions but is not required to perform bounds checks. Using
exceptions in the manner of <code>vector::at</code> could reduce
performance and would also make <code>mdspan</code> unusable in a
freestanding or no-exceptions context.</p>
<p>Note that <code>aligned_accessor</code> does not introduce
<em>additional</em> preconditions beyond those of the existing C++
Standard Library feature <code>assume_aligned</code>. In the words of
one LEWG reviewer, <code>aligned_accessor</code> is not any more
“pointy” than <code>assume_aligned</code>; it just passes the point
through without “blunting” it.</p>
<p>Before submitting R0 of this paper, we considered an approach
specific to <code>aligned_accessor</code>, that would force the
precondition back to <code>mdspan</code> construction time. This
approach would wrap the pointer in a special data handle type with a
constructor that takes a raw pointer, and has a precondition that the
raw pointer has sufficient alignment. The constructor would be
<code>explicit</code>, because it would have a precondition. The design
would look something like this.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, std<span class="op">::</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> aligned_accessor <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> element_type <span class="op">=</span> ElementType;</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> reference <span class="op">=</span> ElementType<span class="op">&amp;</span>;</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> offset_policy <span class="op">=</span> stdex<span class="op">::</span>default_accessor<span class="op">&lt;</span>ElementType<span class="op">&gt;</span>;</span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> data_handle_type <span class="op">{</span></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">public</span><span class="op">:</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> data_handle_type<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Checking the precondition can never be a compile-time</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a>    <span class="co">// expression, so the constructor is not marked constexpr.</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">explicit</span> data_handle_type<span class="op">(</span>element_type<span class="op">*</span> the_data<span class="op">)</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>      <span class="op">:</span> data_<span class="op">(</span>the_data<span class="op">)</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span> <span class="co">// Precondition: null, or sufficiently aligned.</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a>      <span class="ot">assert</span><span class="op">(</span>data_ <span class="op">==</span> <span class="kw">nullptr</span> <span class="op">||</span></span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a>        is_sufficiently_aligned<span class="op">&lt;</span>byte_alignment<span class="op">&gt;(</span>data_<span class="op">))</span>;</span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Conversion is implicit because it has no precondition.</span></span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">operator</span> element_type<span class="op">*</span> <span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb9-23"><a href="#cb9-23" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> data<span class="op">()</span>;</span>
<span id="cb9-24"><a href="#cb9-24" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb9-25"><a href="#cb9-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-26"><a href="#cb9-26" aria-hidden="true" tabindex="-1"></a>  <span class="kw">private</span><span class="op">:</span></span>
<span id="cb9-27"><a href="#cb9-27" aria-hidden="true" tabindex="-1"></a>    element_type<span class="op">*</span> data_ <span class="op">=</span> <span class="kw">nullptr</span>;</span>
<span id="cb9-28"><a href="#cb9-28" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb9-29"><a href="#cb9-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-30"><a href="#cb9-30" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... the omitted parts of aligned_accessor would not change ...</span></span>
<span id="cb9-31"><a href="#cb9-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-32"><a href="#cb9-32" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> reference</span>
<span id="cb9-33"><a href="#cb9-33" aria-hidden="true" tabindex="-1"></a>    access<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span></span>
<span id="cb9-34"><a href="#cb9-34" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb9-35"><a href="#cb9-35" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> assume_aligned<span class="op">&lt;</span>byte_alignment<span class="op">&gt;((</span>element_type<span class="op">*)(</span>p<span class="op">))[</span>i<span class="op">]</span>;</span>
<span id="cb9-36"><a href="#cb9-36" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-37"><a href="#cb9-37" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-38"><a href="#cb9-38" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">typename</span> offset_policy<span class="op">::</span>data_handle_type</span>
<span id="cb9-39"><a href="#cb9-39" aria-hidden="true" tabindex="-1"></a>  offset<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb9-40"><a href="#cb9-40" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">(</span>element_type<span class="op">*)(</span>p<span class="op">)</span> <span class="op">+</span> i;</span>
<span id="cb9-41"><a href="#cb9-41" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb9-42"><a href="#cb9-42" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>Users would have to construct the <code>mdspan</code> 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>element_type<span class="op">*</span> raw_pointer <span class="op">=</span> get_pointer_from_somewhere<span class="op">()</span>;</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> acc_type <span class="op">=</span> aligned_accessor<span class="op">&lt;</span>element_type, byte_alignment<span class="op">&gt;</span>;</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>mdspan x<span class="op">{</span>acc_type<span class="op">::</span>data_handle_type<span class="op">{</span>raw_pointer<span class="op">}</span>, mapping, acc_type<span class="op">{}}</span>;</span></code></pre></div>
<p>We rejected this approach in favor of
<code>is_sufficiently_aligned</code> for the following reasons.</p>
<ol type="1">
<li><p>Wrapping the pointer in a custom data handle class would make
every <code>access</code> or <code>offset</code> call need to reach
through the data handle’s interface, instead of just taking the raw
pointer directly. The <code>access</code> function, and to some extent
also <code>offset</code>, need to be as fast as possible. Their
performance depends on compilers being able to optimize through function
calls. The authors of <code>mdspan</code> carefully balanced generality
with function call depth and other code complexity factors that may
hinder compilers from optimizing. Performance of
<code>aligned_accessor</code> matters as much or even more than
performance of <code>default_accessor</code>, because
<code>aligned_accessor</code> exists to communicate optimization
potential.</p></li>
<li><p>The alignment precondition would still exist. Requiring the data
handle type to throw an exception if the pointer is not sufficiently
aligned would make <code>mdspan</code> unusable in a freestanding or
no-exceptions context.</p></li>
<li><p>Users should not have to pay for unneeded checks. The two
examples in the wording express the two most common cases. If users get
a pointer from a function like <code>aligned_alloc</code>, then they
already know its alignment, because they asked for it. If users are
computing alignment at run time to dispatch to a more optimized code
path, then they know alignment before dispatch. In both cases, users
already know the alignment before constructing the
<code>mdspan</code>.</p></li>
<li><p>The data handle is still a pointer, it’s just a pointer with a
constraint on its values. Users would reasonably expect to be able to
use the result of <code>data_handle()</code> with existing interfaces
that expect a raw pointer.</p></li>
</ol>
<p>An LEWG poll on 2023-10-10, “[b]lock <code>aligned_accessor</code>
progressing until we have a way of checking alignment requirements
during <code>mdspan</code> construction,” resulted in no consensus.
Attendance was 14.</p>
<table>
<tr>
<th>
Strongly Favor
</th>
<th>
Weakly Favor
</th>
<th>
Neutral
</th>
<th>
Weakly Against
</th>
<th>
Strongly Against
</th>
</tr>
<tr>
<th>
0
</th>
<th>
1
</th>
<th>
1
</th>
<th>
2
</th>
<th>
2
</th>
</tr>
</table>
<p>LEWG expressed an (unpolled) interest that we explore
<code>mdspan</code> safety in subsequent work after the fall 2023 Kona
WG21 meeting. LEWG asked us to explore safety in a way that is not
specific to <code>aligned_accessor</code>. Part of that exploration is
in the section below “Generalize <code>is_sufficiently_aligned</code>
for all accessors?”. We plan further exploration of this topic
elsewhere.</p>
<h2 data-number="5.6" id="is_sufficiently_aligned-is-not-constexpr"><span class="header-section-number">5.6</span>
<code>is_sufficiently_aligned</code> is not <code>constexpr</code><a href="#is_sufficiently_aligned-is-not-constexpr" class="self-link"></a></h2>
<p>LEWG reviewed R1 of this proposal at the June 2024 St. Louis WG21
meeting, and polled 1/10/0/0/1 (SF/F/N/A/SA) to remove
<code>constexpr</code> from <code>is_sufficiently_aligned</code>. This
is because it is not clear how to implement the function in a way that
could ever be a constant expression. The straightforward cross-platform
way to implement this would <code>bit_cast</code> the pointer to
<code>uintptr_t</code>. However, <code>bit_cast</code> is not
<code>constexpr</code> when converting from a pointer to an integer, per
<a href="https://eel.is/c++draft/bit.cast#3">[bit.cast] 3</a>. Any
<code>reinterpret_cast</code> similarly could not be a core constant
expression, per
<a href="https://eel.is/c++draft/expr.const#5.15">[expr.const] 5.15</a>.
One LEWG reviewer pointed out that some compilers have a built-in
operation (e.g., Clang and GCC have <code>__builtin_bit_cast</code>)
that might form a constant expression when <code>bit_cast</code> does
not. On the other hand, the authors could not foresee a need for
<code>is_sufficiently_aligned</code> to be <code>constexpr</code> and
did not want to constrain implementations to use compiler-specific
functionality.</p>
<h2 data-number="5.7" id="generalize-is_sufficiently_aligned-for-all-accessors"><span class="header-section-number">5.7</span> Generalize
<code>is_sufficiently_aligned</code> for all accessors?<a href="#generalize-is_sufficiently_aligned-for-all-accessors" class="self-link"></a></h2>
<p>We proposed the <code>is_sufficiently_aligned</code> function so that
users can check a pointer’s alignment precondition before constructing
an <code>aligned_accessor</code> <code>mdspan</code> with it. R4 of this
paper changes <code>is_sufficiently_aligned</code> from a static member
function of <code>aligned_accessor</code> to a nonmember function not in
an <code>mdspan</code> header. C++ developers who do not use
<code>mdspan</code> at all might still find
<code>is_sufficiently_aligned</code> useful, for example to check the
preconditions of <code>assume_aligned</code>.</p>
<p>Nevertheless, in the context of <code>mdspan</code> accessors,
<code>is_sufficiently_aligned</code> is specific to
<code>aligned_accessor</code>. No other <code>mdspan</code> accessors
existing in or proposed for the Standard Library have an alignment
precondition. Furthermore, <code>is_sufficiently_aligned</code> has a
precondition that the pointer points to a valid element. Standard C++
offers no way for users to check that. More importantly for
<code>mdspan</code> users, Standard C++ offers no way to check whether a
pointer and a layout mapping’s <code>required_span_size()</code> form a
valid range.</p>
<p>For this reason, we do not propose here solving the general “is this
data handle valid for an arbitrary given accessor?” question. That is,
we do not propose adding a function to the accessor requirements that
would tell if a given data handle and size pair is valid for that
accessor. This section describes what such a check would look like if it
existed.</p>
<h3 data-number="5.7.1" id="detectably_invalid-generic-validity-check"><span class="header-section-number">5.7.1</span>
<code>detectably_invalid</code>: Generic validity check?<a href="#detectably_invalid-generic-validity-check" class="self-link"></a></h3>
<p>During the June 2024 St. Louis WG21 meeting, one LEWG reviewer
(please see Acknowledgments below) pointed out that code that is generic
on the accessor type currently has no way to check whether a given data
handle is valid. Specifically, given a <code>size_t</code>
<code>size</code> (e.g., the <code>required_span_size()</code> of a
given layout mapping), there is no way to check whether <span class="math inline">[</span> 0, <code>size</code> <span class="math inline">)</span> forms an accessible range (see
<a href="https://eel.is/c++draft/views.multidim#mdspan.accessor.general-2">[mdspan.accessor.general]
2</a>) of a given data handle and accessor. The reviewer suggested
adding a new member function</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type handle, <span class="dt">size_t</span> size<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>to all <code>mdspan</code> accessors. This would return
<code>true</code> if the implementation can show that <span class="math inline">[</span> 0, <code>size</code> <span class="math inline">)</span> is <em>not</em> an accessible range for
<code>handle</code> and the accessor, and <code>true</code> otherwise.
The word “detectably” in the name would remind users that this is a
“best effort” check. It might return <code>false</code> even if the
handle is invalid or if <span class="math inline">[</span> 0,
<code>size</code> <span class="math inline">)</span> is not an
accessible range. Also, it might return different values on different
implementations, depending on their ability to check e.g., pointer range
validity. The function would have the following design features.</p>
<ul>
<li><p>It must be a non-<code>static</code> member function, because in
general, accessors may have state that determines validity of the data
handle.</p></li>
<li><p>It must be <code>const</code> because precondition-checking code
should avoid observable side effects.</p></li>
<li><p>It must be <code>noexcept</code> because precondition-checking
code should not throw.</p></li>
</ul>
<p>With such a function, users could write generic checked
<code>mdspan</code> creation code like the following.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutMapping, <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> create_mdspan_with_check<span class="op">(</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type handle,</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>  LayoutMapping mapping,</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>  Accessor accessor<span class="op">)</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="cf">if</span> <span class="op">(</span>accessor<span class="op">.</span>detectably_invalid<span class="op">(</span>handle, mapping<span class="op">.</span>required_span_size<span class="op">()))</span> <span class="op">{</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">throw</span> std<span class="op">::</span>out_of_range<span class="op">(</span><span class="st">&quot;Invalid data handle and/or size&quot;</span><span class="op">)</span>;</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> mdspan<span class="op">{</span>handle, mapping, accessor<span class="op">}</span>;</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="5.7.2" id="arguments-against-and-for-detectably_invalid"><span class="header-section-number">5.7.2</span> Arguments against and for
<code>detectably_invalid</code><a href="#arguments-against-and-for-detectably_invalid" class="self-link"></a></h3>
<p>We didn’t include this feature in the original <code>mdspan</code>
design because most data handle types have no way to say with full
accuracy whether a handle and size are valid. We didn’t want to give
users the false impression that a validity check was doing anything
meaningful. Standard C++ has no way to check a raw pointer
<code>T*</code> and a size, though some implementations such as CHERI
C++ ([Davis 2019] and [Watson 2020]) and run-time profiling and
debugging systems such as Valgrind do have this feature. We designed
<code>mdspan</code> accessors to be able to wrap libraries that
implement a partitioned global address space (PGAS) programming model
for accessing remote data over a network. (See
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0009r18.html#why-custom-accessors">P0009R18,
Section 2.7, “Why custom accessors?”.</a>) Such libraries include the
one-sided communication interface in MPI (the Message Passing Interface
for distributed-memory parallel programming) or NVSHMEM (NVIDIA’s
implementation of the SHMEM standard). Those libraries define their own
data handle to represent remote data. For example, MPI uses an
<code>MPI_Win</code> “window” object. NVSHMEM uses a C++ pointer to
represent a “symmetric address” that points to an allocation from the
“symmetric heap” (that is accessible to all participating parallel
processes). Such libraries generally do not have validity checks for
their handles.</p>
<p>On the other hand, a <code>detectably_invalid</code> function would
let happen any checks that <em>could</em> happen. For instance, a
hypothetical “GPU device memory accessor” (not proposed for the C++
Standard, but existing in projects like
<a href="https://github.com/rapidsai/raft">RAPIDS RAFT</a>) might permit
access to an allocation of GPU “device” memory from only GPU “device”
code, not from ordinary “host” code. A common use case for GPU
allocations is to allocate device memory in host code, then pass the
pointer to device code for use there. Thus, it would be reasonable to
create an <code>mdspan</code> in host code with that accessor. The
accessor could use a CUDA run-time function like
<a href="https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__UNIFIED.html"><code>cudaPointerGetAttributes</code></a>
to check if the pointer points to valid GPU memory. Even
<code>default_accessor</code> could have a simple check like this.</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="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type ptr, <span class="dt">size_t</span> size<span class="op">)</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="kw">noexcept</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> ptr <span class="op">==</span> <span class="kw">nullptr</span> <span class="op">&amp;&amp;</span> size <span class="op">!=</span> <span class="dv">0</span>;</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="5.7.3" id="users-could-work-around-the-breaking-change-of-adding-detectably_invalid-to-accessor-requirements"><span class="header-section-number">5.7.3</span> Users could work around the
breaking change of adding <code>detectably_invalid</code> to accessor
requirements<a href="#users-could-work-around-the-breaking-change-of-adding-detectably_invalid-to-accessor-requirements" class="self-link"></a></h3>
<p>C++23 defines the generic interface of accessors through the accessor
policy requirements
<a href="https://eel.is/c++draft/mdspan.accessor.reqmts"><strong>[mdspan.accessor.reqmts]</strong></a>.
Adding <code>detectably_invalid</code> to these requirements would be a
breaking change to C++23. Thus, generic code that wanted to call this
function would need to fill in default behavior for both Standard
accessors defined in C++23, and user-defined accessors that comply with
the C++23 accessor requirements. The following
<code>detectably_invalid</code> nonmember function (not proposed in this
paper) shows one way users could do that. Please see Appendix A below
for the full source code of a demonstration, along with a Compiler
Explorer link. This demonstration shows that breaking backwards
compatibility with C++23 is unnecessary, because users can
straightforwardly work around the lack of a
<code>detectably_invalid</code> member function in C++23 - compliant
accessors. Not standardizing this nonmember function work-around would
also give users the freedom to fill in different default behavior. For
example, some users may prefer to consider every (data handle, size)
pair invalid unless proven otherwise, as a way to force use of custom
accessors that have the ability to make accurate checks.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> has_detectably_invalid <span class="op">=</span> <span class="kw">requires</span><span class="op">(</span>Accessor acc<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type;</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span> std<span class="op">::</span>as_const<span class="op">(</span>acc<span class="op">).</span>detectably_invalid<span class="op">(</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>declval<span class="op">&lt;</span><span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type<span class="op">&gt;()</span>,</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>declval<span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span><span class="op">&gt;()</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">)</span> <span class="op">}</span> <span class="kw">noexcept</span> <span class="op">-&gt;</span> std<span class="op">::</span>same_as<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span>;</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> detectably_invalid<span class="op">(</span>Accessor<span class="op">&amp;&amp;</span> accessor,</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>Accessor<span class="op">&gt;::</span>data_handle_type handle,</span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>has_detectably_invalid<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>Accessor<span class="op">&gt;&gt;)</span> <span class="op">{</span></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>as_const<span class="op">(</span>accessor<span class="op">).</span>detectably_invalid<span class="op">(</span>handle, size<span class="op">)</span>;</span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="5.7.4" id="is_sufficiently_aligned-is-still-useful-on-its-own"><span class="header-section-number">5.7.4</span>
<code>is_sufficiently_aligned</code> is still useful on its own<a href="#is_sufficiently_aligned-is-still-useful-on-its-own" class="self-link"></a></h3>
<p>One could argue that if <code>aligned_accessor</code> had
<code>detectably_invalid</code>, that would make
<code>is_sufficiently_aligned</code> unnecessary. We disagree; we think
<code>is_sufficiently_aligned</code> is useful by itself, whether or not
<code>detectably_invalid</code> exists, for the following reasons.</p>
<ol type="1">
<li><p>Users will often want to check alignment separately from pointer
range validity.</p></li>
<li><p>Checking alignment may be much less expensive than checking
pointer range validity.</p></li>
<li><p>As of R4 of this paper, <code>is_sufficiently_aligned</code> is
available without including an <code>mdspan</code> header, and thus is
useful even to those who do not adopt <code>mdspan</code>.</p></li>
</ol>
<p>Regarding (1), we think the most common use case for
<code>aligned_accessor</code>’s <code>explicit</code> converting
constructor from <code>default_accessor</code> would be explicit
construction of an <code>mdspan</code> with
<code>aligned_accessor</code> from an <code>mdspan</code> with
<code>default_accessor</code>. The latter exists, so the user has
already asserted that the range formed by its data handle and
<code>required_span_size()</code> is valid. Thus, the only thing the
user would need to check would be whether the data handle is
sufficiently aligned.</p>
<p>The same LEWG reviewer who suggested <code>detectably_invalid</code>
had originally thought it would make
<code>is_sufficiently_aligned</code> unnecessary. However, after
reviewing R2 of this paper, that reviewer changed their mind. They now
agree with us that <code>is_sufficiently_aligned</code> is useful by
itself. All their concerns would be addressed by making
<code>is_sufficiently_aligned</code> a nonmember function, rather than a
member function of <code>aligned_accessor</code>.</p>
<h3 data-number="5.7.5" id="nonmember-is_sufficiently_aligned"><span class="header-section-number">5.7.5</span> Nonmember
<code>is_sufficiently_aligned</code><a href="#nonmember-is_sufficiently_aligned" class="self-link"></a></h3>
<p>The reviewer responded to our argument above by suggesting that we
remove <code>is_sufficiently_aligned</code> from
<code>aligned_accessor</code> and make it a separate nonmember function.
R4 of this paper implements this change.</p>
<h4 data-number="5.7.5.1" id="mark-it-freestanding"><span class="header-section-number">5.7.5.1</span> Mark it freestanding<a href="#mark-it-freestanding" class="self-link"></a></h4>
<p>We propose marking <code>is_sufficiently_aligned</code> freestanding.
We know of no obstacles to this. Since <code>assume_aligned</code> is
freestanding and since it would be reasonable to use
<code>is_sufficiently_aligned</code> and <code>assume_aligned</code>
together, it would make sense to mark
<code>is_sufficiently_aligned</code> freestanding as well.</p>
<h4 data-number="5.7.5.2" id="put-it-in-memory"><span class="header-section-number">5.7.5.2</span> Put it in
<code>&lt;memory&gt;</code><a href="#put-it-in-memory" class="self-link"></a></h4>
<p>Into which header should this new function go? Since
<code>is_sufficiently_aligned</code> does not depend on
<code>mdspan</code>, it should not live in an <code>mdspan</code>
header. It should be usable in any place that
<code>assume_aligned</code> can be used. R4 proposed putting it in
<code>&lt;bit&gt;</code>, because it is fundamentally a bit arithmetic
operation. However, LEWG mailing list feedback expressed a strong
preference for the function to go in <code>&lt;memory&gt;</code>
instead. First, that would make it easier to use
<code>is_sufficiently_aligned</code> and <code>assume_aligned</code>
together. Second, “alignment is related to placement of the object in
memory,” as one LEWG mailing list reviewer pointed out. R5 thus proposes
putting the function in <code>&lt;memory&gt;</code>.</p>
<h4 data-number="5.7.5.3" id="throws-nothing"><span class="header-section-number">5.7.5.3</span> Throws: Nothing<a href="#throws-nothing" class="self-link"></a></h4>
<p>R5 also adds a “<em>Throws</em>: Nothing” element to
<code>is_sufficiently_aligned</code>. Users generally would not want
<code>is_sufficiently_aligned</code> to throw, because it exists to
check a precondition of <code>assume_aligned</code>.</p>
<p>Note that the function is <em>not</em> declared
<code>noexcept</code>. This is because the function has a precondition,
that its input <code>T* ptr</code> points to an object of a type similar
to <code>T</code>. As we explained in the
<code>detectably_invalid</code> discussion above, implementations do
exist that can check this precondition. In practice, the most common use
cases for <code>is_sufficiently_aligned</code> are analogous to use of
<code>dynamic_cast</code> for class hierarchies. Users start with a
valid pointer with unknown alignment (analogous to a valid pointer to a
base class <code>Base</code>), then assert or determine its alignment at
run time (analogous to <code>dynamic_cast</code>ing the pointer to a
subclass of <code>Base</code>, and checking if the result is null).</p>
<h3 data-number="5.7.6" id="do-accessors-need-to-check-anything-else"><span class="header-section-number">5.7.6</span> Do accessors need to check
anything else?<a href="#do-accessors-need-to-check-anything-else" class="self-link"></a></h3>
<p>The only other thing an accessor’s user might want to check besides a
(data handle, size) pair would be converting construction from another
type of accessor. All <code>mdspan</code> components –
<code>extents</code>, layout mappings, and accessors – implement
conversions with preconditions via <code>explicit</code> constructors.
(For more detail, please see the section below, “Explicit conversions as
the model for precondition-asserting conversions.”) Accessors do
<em>not</em> store their data handles, so the only reason to check
whether converting construction is valid would be if the input or result
accessor has separate run-time state. (Otherwise, the check could be a
constraint or <code>static_assert</code>.) It’s rare for an accessor to
need run-time state, so we don’t expect to need this feature in generic
code. It would also be a separable addition from the feature of checking
a data handle and size. Nevertheless, one could consider a design. We
would favor just overloading <code>detectably_invalid</code> for
accessors, as there would be no risk of ambiguity. Converting
constructors only take one argument, so there would be no ambiguity
between calling <code>detectably_invalid</code> with an accessor and
calling it with a data handle and size.</p>
<h3 data-number="5.7.7" id="naming-the-function"><span class="header-section-number">5.7.7</span> Naming the function<a href="#naming-the-function" class="self-link"></a></h3>
<ol type="1">
<li><p>The function describes a property: “this (data handle, size) pair
is not known to be invalid.” It’s an adjective (like
“<code>valid</code>” or “<code>is_valid</code>”), not a verb (like
“check” as in “<code>check_valid</code>”).</p></li>
<li><p>The function does not promise perfect accuracy. In the common
case, it says whether it can <em>detect</em> whether the handle and size
are <em>not</em> valid. Whether they are <em>valid</em> might be harder
to say.</p></li>
<li><p>As discussed above, users may also want to check converting
constructors from other accessor types. However, there would be no risk
of ambiguity between that and checking a data handle and size.
Therefore, there’s no need for the function’s name to include the type
of the thing being checked (e.g., “range”).</p></li>
<li><p>Specifically, the function should not contain the word “pointer,”
because a data handle is not necessarily a pointer. Even if
<code>data_handle_type</code>​ is a pointer type, a data handle might not
necessarily be a pointer to the elements in the Standard C++ sense. For
example, it might be some opaque handle that a library represents as a
type alias of <code>void*</code>​.</p></li>
</ol>
<p>These points together suggest the name
<code>detectably_invalid</code>.</p>
<h3 data-number="5.7.8" id="conclusions"><span class="header-section-number">5.7.8</span> Conclusions<a href="#conclusions" class="self-link"></a></h3>
<ol type="1">
<li><p>Adding <code>detectably_invalid</code> to the accessor
requirements and existing Standard accessors in C++26 would be a
breaking change to C++23. Nevertheless, even with this breaking change,
users could still write code that fills in reasonable behavior for C++23
accessors.</p></li>
<li><p>Few C++ implementations offer a way to check validity of a
pointer range. Thus, users would experience
<code>detectably_invalid</code> as mostly not useful for the common case
of <code>default_accessor</code> and other accessors that access a
pointer range.</p></li>
<li><p>Item (1) reduces the urgency of adding
<code>detectably_invalid</code> to C++26. Item (2) reduces its potential
to improve the <code>mdspan</code> user experience in a practical way.
Therefore, we do not suggest adding <code>detectably_invalid</code> to
the accessor requirements in this proposal. However, we do not
discourage further work in separate proposals.</p></li>
<li><p>R4 of this paper removes <code>is_sufficiently_aligned</code>
from <code>aligned_accessor</code> and adds it to the Standard Library
as a separate nonmember function. R5 puts it in the
<code>&lt;memory&gt;</code> header.</p></li>
</ol>
<h2 data-number="5.8" id="explicit-conversions-as-the-model-for-precondition-asserting-conversions"><span class="header-section-number">5.8</span> Explicit conversions as the
model for precondition-asserting conversions<a href="#explicit-conversions-as-the-model-for-precondition-asserting-conversions" class="self-link"></a></h2>
<p>During the June 2024 St. Louis WG21 meeting, one LEWG reviewer asked
about the <code>explicit</code> constructor from
<code>default_accessor</code>. This constructor lets users assert that a
pointer has sufficient alignment to be accessed by the
<code>aligned_accessor</code>. The reviewer argued that this was an
“unsafe” conversion, and wanted these “unsafe” conversions to be even
more explicit than an <code>explicit</code> constructor: e.g., a new
<code>*_cast</code> function template. We do not agree with this idea;
this section explains why.</p>
<h3 data-number="5.8.1" id="example-conversion-to-aligned_accessor"><span class="header-section-number">5.8.1</span> Example: conversion to
<code>aligned_accessor</code><a href="#example-conversion-to-aligned_accessor" class="self-link"></a></h3>
<p>Suppose that some function that users can’t change returns an
<code>mdspan</code> of <code>float</code> with
<code>default_accessor</code>, even though users know that the
<code>mdspan</code> is overaligned to <code>8 * sizeof(float)</code>
bytes. The function’s parameter(s) don’t matter for this example.</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>mdspan<span class="op">&lt;</span><span class="dt">float</span>, dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, layout_right, default_accessor<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  overaligned_view<span class="op">(</span>SomeParameters params<span class="op">)</span>;</span></code></pre></div>
<p>Suppose also that users want to call some other function that they
can’t change. This function takes an <code>mdspan</code> of
<code>float</code> with <code>aligned_accessor&lt;float, 8&gt;</code>.
Its return type doesn’t matter for this example.</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>SomeReturnType use_overaligned_view<span class="op">(</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">float</span>, dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, layout_right, aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;)</span>;</span></code></pre></div>
<h3 data-number="5.8.2" id="status-quo"><span class="header-section-number">5.8.2</span> Status quo<a href="#status-quo" class="self-link"></a></h3>
<p>How do users call <code>use_overaligned_view</code> with the object
returned from <code>overaligned_view</code>? The status quo offers two
ways. Both of them rely on
<code>aligned_accessor&lt;float, 8&gt;</code>’s <code>explicit</code>
converting constructor from
<code>default_accessor&lt;float&gt;</code>.</p>
<ol type="1">
<li><p>Use <code>mdspan</code>’s <code>explicit</code> converting
constructor.</p></li>
<li><p>Construct the new <code>mdspan</code> explicitly from its data
handle, layout mapping, and accessor. (This is the ideal use case for
CTAD, as an <code>mdspan</code> is nothing more than its data handle,
layout mapping, and accessor.)</p></li>
</ol>
<p>Way (1) looks like this.</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> x <span class="op">=</span> overaligned_view<span class="op">(</span>params<span class="op">)</span>;</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">float</span>, dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, layout_right,</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;(</span>x<span class="op">)</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>Way (2) looks like this. Note use of CTAD.</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> x <span class="op">=</span> overaligned_view<span class="op">(</span>params<span class="op">)</span>;</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">{</span>x<span class="op">.</span>data_handle<span class="op">()</span>, x<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;(</span>x<span class="op">.</span>accessor<span class="op">())}</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>Which way is less verbose depends on <code>mdspan</code>’s template
arguments. Both ways, though, force the user to name the type
<code>aligned_accessor&lt;float, 8&gt;</code> explicitly. Users know
that they have pulled out a sharp knife from the toolbox. It’s verbose,
it’s nondefault, and it’s a class with a short definition. Users can go
to the specification, see <code>assume_aligned</code>, and know they are
dealing with a low-level function that has a precondition.</p>
<h3 data-number="5.8.3" id="mdspan-uses-explicit-conversions-to-assert-preconditions"><span class="header-section-number">5.8.3</span> <code>mdspan</code> uses
explicit conversions to assert preconditions<a href="#mdspan-uses-explicit-conversions-to-assert-preconditions" class="self-link"></a></h3>
<p>The entire system of <code>mdspan</code> components was designed so
that</p>
<ul>
<li><p>conversions with preconditions happen through
<code>explicit</code> conversions (mostly converting constructors);
while</p></li>
<li><p>conversions without preconditions happen through implicit
conversions.</p></li>
</ul>
<p>Changing this would break backwards compatibility with C++23. For
example, one can see this with converting constructors for</p>
<ul>
<li><p><code>extents</code> (for conversions from run-time to
compile-time extents, or conversions from wider to narrower index type):
<a href="https://eel.is/c++draft/mdspan.extents.cons">[mdspan.extents.cons]</a>;
and</p></li>
<li><p><code>layout_left::mapping</code>, and all the other layout
mappings currently in the Standard that are not
<code>layout_stride</code> or <code>layout_transpose</code> (for
conversions from e.g., <code>layout_stride::mapping</code>, which assert
that the strides are compatible): e.g.,
<a href="https://eel.is/c++draft/mdspan.layout.left.cons">[mdspan.layout.left.cons]</a>.</p></li>
</ul>
<p>This is consistent with C++ Standard Library class templates, in that
construction asserts any preconditions. For example, if users construct
a <code>string_view</code> or <code>span</code> from a pointer
<code>ptr</code> and a size <code>size</code>, this asserts that the
range <span class="math inline">[</span> <code>ptr</code>,
<code>ptr + size</code> <span class="math inline">)</span> is
accessible.</p>
<h3 data-number="5.8.4" id="alternative-explicit-cast-function-naughty_cast"><span class="header-section-number">5.8.4</span> Alternative: explicit cast
function <code>naughty_cast</code><a href="#alternative-explicit-cast-function-naughty_cast" class="self-link"></a></h3>
<p>Everything we have described above is the status quo. What did the
one LEWG reviewer want to see? They wanted all conversions with
preconditions to use a “cast” function with an easily searchable name,
analogous to <code>static_cast</code>. As a placeholder, we’ll call it
“<code>naughty_cast</code>.” For the above
<code>use_overaligned_view</code> example, the <code>naughty_cast</code>
analog of Way (2) would look like this.</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><span class="kw">auto</span> x <span class="op">=</span> overaligned_view<span class="op">(</span>params<span class="op">)</span>;</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">{</span>x<span class="op">.</span>data_handle<span class="op">()</span>, x<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>    naughty_cast<span class="op">&lt;</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;&gt;(</span>x<span class="op">.</span>accessor<span class="op">())}</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>One could imagine defining <code>naughty_cast</code> of
<code>mdspan</code> by <code>naughty_cast</code> of its components. This
would enable an analog of Way (1).</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> x <span class="op">=</span> overaligned_view<span class="op">(</span>params<span class="op">)</span>;</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span>naughty_cast<span class="op">&lt;</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">float</span>, dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, layout_right,</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;&gt;(</span>x<span class="op">)</span></span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>Another argument for <code>naughty_cast</code> besides searchability
is to make conversions with preconditions “loud,” that is, easily seen
in the code by human developers. However, the original Way (1) and Way
(2) both are loud already in that they require a lot of extra code that
spells out the result’s accessor type explicitly. The status quo’s
difference in “volume” is implicit conversion</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span>x<span class="op">)</span>;</span></code></pre></div>
<p>versus explicit construction.</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><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">{</span>x<span class="op">.</span>data_handle<span class="op">()</span>, x<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;(</span>x<span class="op">)})</span>;</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>Adding <code>naughty_cast</code> to the latter doesn’t make it much
louder.</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">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">{</span>x<span class="op">.</span>data_handle<span class="op">()</span>, x<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    naughty_cast<span class="op">&lt;</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;(</span>x<span class="op">)})</span>;</span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>There are other disadvantages to a <code>naughty_cast</code> design.
The point of that design would be to remove or make
non-<code>public</code> all the <code>explicit</code> constructors from
<code>mdspan</code>’s components. That functionality would need to move
somewhere. A typical implementation technique for a custom cast function
is to rely on specializations of a struct with two template parameters,
one for the input type and one for the output type of the cast. The
<code>naughty_caster</code> struct example below shows how one could do
that.</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Output, <span class="kw">class</span> Input<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> naughty_caster <span class="op">{}</span>;</span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Output, <span class="kw">class</span> Input<span class="op">&gt;</span></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a>Output naughty_cast<span class="op">(</span><span class="kw">const</span> Input<span class="op">&amp;</span> input<span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> naughty_caster<span class="op">&lt;</span>Output, Input<span class="op">&gt;::</span>cast<span class="op">(</span>input<span class="op">)</span>;</span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OutputElementType, <span class="dt">size_t</span> ByteAlignment,</span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> InputElementType<span class="op">&gt;</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span>is_convertible_v<span class="op">&lt;</span>InputElementType<span class="op">(*)[]</span>,</span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a>    OutputElementType<span class="op">(*)[]&gt;)</span> </span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> naughty_caster <span class="op">{</span></span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> output_type <span class="op">=</span></span>
<span id="cb24-15"><a href="#cb24-15" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span>OutputElementType, ByteAlignment<span class="op">&gt;</span>;</span>
<span id="cb24-16"><a href="#cb24-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> input_type <span class="op">=</span> default_accessor<span class="op">&lt;</span>InputElementType<span class="op">&gt;</span>;</span>
<span id="cb24-17"><a href="#cb24-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-18"><a href="#cb24-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> output_type cast<span class="op">(</span><span class="kw">const</span> input_type<span class="op">&amp;)</span> <span class="op">{</span></span>
<span id="cb24-19"><a href="#cb24-19" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">{}</span>; </span>
<span id="cb24-20"><a href="#cb24-20" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb24-21"><a href="#cb24-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>This technique takes a lot of effort and code, when by far the common
case is that <code>cast</code> has a trivial body. For any accessors
with state, it would almost certainly call for breaks of encapsulation,
like making the <code>naughty_caster</code> specialization a
<code>friend</code> of the input and/or output.</p>
<p>We emphasize that users are meant to write custom accessors. The
intended typical author of a custom accessor is a performance expert who
is not necessarily a C++ expert. It takes quite a bit of C++ experience
to learn how to use encapsulation-breaking techniques safely; other
approaches all just expose implementation details or defeat the “safety”
that <code>naughty_cast</code> is supposed to introduce. Given that the
main motivation of <code>naughty_cast</code> is safety, we shouldn’t
make it harder for users to write safe code.</p>
<p>More importantly, <code>naughty_cast</code> would obfuscate
accessors. The architects of <code>mdspan</code> meant accessors to have
to have a small number of “moving parts” and to define all those parts
in a single place. Contrast <code>default_accessor</code> with the
contiguous iterator requirements, for instance. The
<code>naughty_cast</code> design would force custom accessors (and
custom layouts) to define their different parts in different places,
rather than all in one class. WG21 has moved away from this scattered
design approach. For example,
<a href="https://wg21.link/p2855r1">P2855R1</a> (“Member customization
points for Senders and Receivers”) changes P2300 (std::execution) to use
member functions instead of <code>tag_invoke</code>-based customization
points.</p>
<h3 data-number="5.8.5" id="conclusion-retain-mdspans-current-design"><span class="header-section-number">5.8.5</span> Conclusion: retain
<code>mdspan</code>’s current design<a href="#conclusion-retain-mdspans-current-design" class="self-link"></a></h3>
<p>For all these reasons, we do not support replacing
<code>mdspan</code>’s current “conversions with preconditions are
explicit conversions” design with a cast function design.</p>
<h1 data-number="6" id="implementation"><span class="header-section-number">6</span> Implementation<a href="#implementation" class="self-link"></a></h1>
<p>We have tested an implementation of this proposal with the <a href="https://github.com/kokkos/mdspan/">reference mdspan
implementation</a>. Appendix B below lists the source code of a full
implementation.</p>
<h1 data-number="7" id="example"><span class="header-section-number">7</span> Example<a href="#example" class="self-link"></a></h1>
<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="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span></span>
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span>,</span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span>, <span class="dt">int</span><span class="op">&gt;</span>,</span>
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>layout_right,</span>
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a><span class="co">// Interfaces that require 32-byte alignment,</span></span>
<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a><span class="co">// because they want to do 8-wide SIMD of float.</span></span>
<span id="cb25-10"><a href="#cb25-10" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span> vectorized_axpy<span class="op">(</span></span>
<span id="cb25-11"><a href="#cb25-11" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y, <span class="dt">float</span> alpha, aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> x<span class="op">)</span>;</span>
<span id="cb25-12"><a href="#cb25-12" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">float</span> vectorized_norm<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y<span class="op">)</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="co">// Interfaces that require 16-byte alignment,</span></span>
<span id="cb25-15"><a href="#cb25-15" aria-hidden="true" tabindex="-1"></a><span class="co">// because they want to do 4-wide SIMD of float.</span></span>
<span id="cb25-16"><a href="#cb25-16" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span> fill_x<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">16</span><span class="op">&gt;</span> x<span class="op">)</span>;</span>
<span id="cb25-17"><a href="#cb25-17" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span> fill_y<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">16</span><span class="op">&gt;</span> y<span class="op">)</span>;</span>
<span id="cb25-18"><a href="#cb25-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-19"><a href="#cb25-19" aria-hidden="true" tabindex="-1"></a><span class="co">// Helper functions for overaligned array allocations.</span></span>
<span id="cb25-20"><a href="#cb25-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-21"><a href="#cb25-21" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb25-22"><a href="#cb25-22" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> delete_raw <span class="op">{</span></span>
<span id="cb25-23"><a href="#cb25-23" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> <span class="kw">operator</span><span class="op">()(</span>ElementType<span class="op">*</span> p<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb25-24"><a href="#cb25-24" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>free<span class="op">(</span>p<span class="op">)</span>;</span>
<span id="cb25-25"><a href="#cb25-25" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb25-26"><a href="#cb25-26" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb25-27"><a href="#cb25-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-28"><a href="#cb25-28" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb25-29"><a href="#cb25-29" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> allocation <span class="op">=</span></span>
<span id="cb25-30"><a href="#cb25-30" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>ElementType<span class="op">[]</span>, delete_raw<span class="op">&lt;</span>ElementType<span class="op">&gt;&gt;</span>;</span>
<span id="cb25-31"><a href="#cb25-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-32"><a href="#cb25-32" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, std<span class="op">::</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb25-33"><a href="#cb25-33" aria-hidden="true" tabindex="-1"></a>allocation<span class="op">&lt;</span>ElementType<span class="op">&gt;</span></span>
<span id="cb25-34"><a href="#cb25-34" aria-hidden="true" tabindex="-1"></a>  allocate_raw<span class="op">(</span><span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> num_elements<span class="op">)</span></span>
<span id="cb25-35"><a href="#cb25-35" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb25-36"><a href="#cb25-36" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> num_bytes <span class="op">=</span> num_elements <span class="op">*</span> <span class="kw">sizeof</span><span class="op">(</span>ElementType<span class="op">)</span>;</span>
<span id="cb25-37"><a href="#cb25-37" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span><span class="op">*</span> ptr <span class="op">=</span> std<span class="op">::</span>aligned_alloc<span class="op">(</span>byte_alignment, num_bytes<span class="op">)</span>;</span>
<span id="cb25-38"><a href="#cb25-38" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">{</span>ptr, delete_raw<span class="op">&lt;</span>ElementType<span class="op">&gt;{}}</span>;</span>
<span id="cb25-39"><a href="#cb25-39" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb25-40"><a href="#cb25-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-41"><a href="#cb25-41" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> user_function<span class="op">(</span><span class="dt">size_t</span> num_elements, <span class="dt">float</span> alpha<span class="op">)</span></span>
<span id="cb25-42"><a href="#cb25-42" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb25-43"><a href="#cb25-43" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Code using the above two interfaces needs to allocate</span></span>
<span id="cb25-44"><a href="#cb25-44" aria-hidden="true" tabindex="-1"></a>  <span class="co">// to the max alignment.  Users could also query</span></span>
<span id="cb25-45"><a href="#cb25-45" aria-hidden="true" tabindex="-1"></a>  <span class="co">// aligned_accessor::byte_alignment for the various interfaces</span></span>
<span id="cb25-46"><a href="#cb25-46" aria-hidden="true" tabindex="-1"></a>  <span class="co">// and take the max.</span></span>
<span id="cb25-47"><a href="#cb25-47" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">size_t</span> max_byte_alignment <span class="op">=</span> <span class="dv">32</span>;</span>
<span id="cb25-48"><a href="#cb25-48" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_alloc <span class="op">=</span> allocate_raw<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb25-49"><a href="#cb25-49" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> y_alloc <span class="op">=</span> allocate_raw<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb25-50"><a href="#cb25-50" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-51"><a href="#cb25-51" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> x<span class="op">(</span>x_alloc<span class="op">.</span>get<span class="op">())</span>;</span>
<span id="cb25-52"><a href="#cb25-52" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> y<span class="op">(</span>y_alloc<span class="op">.</span>get<span class="op">())</span>;</span>
<span id="cb25-53"><a href="#cb25-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-54"><a href="#cb25-54" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Two automatic conversions from 32-byte aligned to 16-byte aligned</span></span>
<span id="cb25-55"><a href="#cb25-55" aria-hidden="true" tabindex="-1"></a>  fill_x<span class="op">(</span>x<span class="op">)</span>;</span>
<span id="cb25-56"><a href="#cb25-56" aria-hidden="true" tabindex="-1"></a>  fill_y<span class="op">(</span>y<span class="op">)</span>;</span>
<span id="cb25-57"><a href="#cb25-57" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-58"><a href="#cb25-58" aria-hidden="true" tabindex="-1"></a>  <span class="co">// These interfaces use 32-byte alignment directly.</span></span>
<span id="cb25-59"><a href="#cb25-59" aria-hidden="true" tabindex="-1"></a>  vectorized_axpy<span class="op">(</span>y, alpha, x<span class="op">)</span>;</span>
<span id="cb25-60"><a href="#cb25-60" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> vectorized_norm<span class="op">(</span>y<span class="op">)</span>;</span>
<span id="cb25-61"><a href="#cb25-61" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="8" id="references"><span class="header-section-number">8</span> References<a href="#references" class="self-link"></a></h1>
<ul>
<li><p>Davis et al., “CheriABI: Enforcing Valid Pointer Provenance and
Minimizing Pointer Privilege in the POSIX C Run-time Environment,”
ASPLOS ’19, April 2019, pp. 379 - 393. Available online [last accessed
2024-07-05]:
<a href="https://dl.acm.org/doi/10.1145/3297858.3304042">https://dl.acm.org/doi/10.1145/3297858.3304042</a></p></li>
<li><p>Watson et al., “CHERI C/C++ Programming Guide,” Technical Report
UCAM-CL-TR-947, University of Cambridge Computer Laboratory, June 2020.
Available online [last accessed 2024-07-05]:
<a href="https://doi.org/10.48456/tr-947">https://doi.org/10.48456/tr-947</a></p></li>
</ul>
<h1 data-number="9" id="acknowledgments"><span class="header-section-number">9</span> Acknowledgments<a href="#acknowledgments" class="self-link"></a></h1>
<ul>
<li>For <code>detectably_invalid</code>, credit (with permission) to
David Sankel (Adobe), <code>dsankel@adobe.com</code></li>
</ul>
<h1 data-number="10" id="wording"><span class="header-section-number">10</span> Wording<a href="#wording" class="self-link"></a></h1>
<blockquote>
<p>Text in blockquotes is not proposed wording, but rather instructions
for generating proposed wording. The � character is used to denote a
placeholder section number which the editor shall determine.</p>
<p>In <strong>[version.syn]</strong>, add</p>
</blockquote>
<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="pp">#define __cpp_lib_aligned_accessor </span>YYYYMML<span class="pp"> </span><span class="co">// also in &lt;mdspan&gt;</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#define __cpp_lib_is_sufficiently_aligned </span>YYYYMML<span class="pp"> </span><span class="co">// also in &lt;memory&gt;</span></span></code></pre></div>
<blockquote>
<p>Adjust the placeholder value <code>YYYYMML</code> as needed so as to
denote this proposal’s date of adoption.</p>
<p>To the Header <code>&lt;memory&gt;</code> synopsis
<strong>[memory.syn]</strong>, after the declaration of
<code>assume_aligned</code> and before the declarations of functions in
<strong>[obj.lifetime]</strong>, add the following.</p>
</blockquote>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="dt">size_t</span> alignment<span class="op">&gt;</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> is_sufficiently_aligned<span class="op">(</span>T<span class="op">*</span> ptr<span class="op">)</span>;</span></code></pre></div>
<blockquote>
<p>At the end of <strong>[ptr.align]</strong>, add the following.</p>
</blockquote>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="dt">size_t</span> alignment<span class="op">&gt;</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> is_sufficiently_aligned<span class="op">(</span>T<span class="op">*</span> ptr<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Preconditions</em>: <code>p</code> points to an object
<code>X</code> of a type similar (<strong>[conv.qual]</strong>) to
<code>T</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Returns</em>: <code>true</code> if <code>X</code> has alignment at
least <code>alignment</code>, else <code>false</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Throws</em>: Nothing.</p>
<blockquote>
<p>To the Header <code>&lt;mdspan&gt;</code> synopsis
<strong>[mdspan.syn]</strong>, after <code>class default_accessor</code>
and before <code>class mdspan</code>, add the following.</p>
</blockquote>
<h2 data-number="10.1" id="add-aligned_accessor-declaration-to-mdspan-header-synopsis"><span class="header-section-number">10.1</span> Add
<code>aligned_accessor</code> declaration to <code>&lt;mdspan&gt;</code>
header synopsis<a href="#add-aligned_accessor-declaration-to-mdspan-header-synopsis" class="self-link"></a></h2>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="co">// [mdspan.accessor.aligned], class template aligned_accessor</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> aligned_accessor;</span></code></pre></div>
<blockquote>
<p>At the end of <strong>[mdspan.accessor.default]</strong> and before
<strong>[mdspan.mdspan]</strong>, add the following.</p>
</blockquote>
<h2 data-number="10.2" id="add-subsection-mdspan.accessor.aligned-with-the-following"><span class="header-section-number">10.2</span> Add subsection �
[mdspan.accessor.aligned] with the following<a href="#add-subsection-mdspan.accessor.aligned-with-the-following" class="self-link"></a></h2>
<p><b> � Class template <code>aligned_accessor</code>
[mdspan.accessor.aligned] </b></p>
<p><b> �.1 Overview [mdspan.accessor.aligned.overview] </b></p>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="dt">size_t</span> the_byte_alignment<span class="op">&gt;</span></span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> aligned_accessor <span class="op">{</span></span>
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> offset_policy <span class="op">=</span> default_accessor<span class="op">&lt;</span>ElementType<span class="op">&gt;</span>;</span>
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> element_type <span class="op">=</span> ElementType;</span>
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> reference <span class="op">=</span> ElementType<span class="op">&amp;</span>;</span>
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> ElementType<span class="op">*</span>;</span>
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> byte_alignment <span class="op">=</span> the_byte_alignment;</span>
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> aligned_accessor<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb30-11"><a href="#cb30-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-12"><a href="#cb30-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType, <span class="dt">size_t</span> other_byte_alignment<span class="op">&gt;</span></span>
<span id="cb30-13"><a href="#cb30-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb30-14"><a href="#cb30-14" aria-hidden="true" tabindex="-1"></a>      aligned_accessor<span class="op">&lt;</span>OtherElementType, other_byte_alignment<span class="op">&gt;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb30-15"><a href="#cb30-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-16"><a href="#cb30-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType<span class="op">&gt;</span></span>
<span id="cb30-17"><a href="#cb30-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">explicit</span> <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb30-18"><a href="#cb30-18" aria-hidden="true" tabindex="-1"></a>      default_accessor<span class="op">&lt;</span>OtherElementType<span class="op">&gt;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb30-19"><a href="#cb30-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-20"><a href="#cb30-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">operator</span> default_accessor<span class="op">&lt;</span>element_type<span class="op">&gt;()</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb30-21"><a href="#cb30-21" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb30-22"><a href="#cb30-22" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb30-23"><a href="#cb30-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-24"><a href="#cb30-24" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> reference access<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb30-25"><a href="#cb30-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb30-26"><a href="#cb30-26" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">typename</span> offset_policy<span class="op">::</span>data_handle_type</span>
<span id="cb30-27"><a href="#cb30-27" aria-hidden="true" tabindex="-1"></a>    offset<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb30-28"><a href="#cb30-28" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Mandates</em>:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>byte_alignment</code> is a power of two, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>byte_alignment &gt;= alignof(ElementType)</code> is
<code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<code>aligned_accessor</code> meets the accessor policy
requirements.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<code>ElementType</code> is required to be a complete object type that
is neither an abstract class type nor an array type.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Each specialization of <code>aligned_accessor</code> is a trivially
copyable type that models <code>semiregular</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<span class="math inline">[0, <em>n</em>)</span> is an accessible range
for an object <code>p</code> of type <code>data_handle_type</code> and
an object of type <code>aligned_accessor</code> if and only if <span class="math inline">[</span><code>p</code>, <code>p</code> + <span class="math inline"><em>n</em>)</span> is a valid range.</p>
<h2 data-number="10.3" id="members-mdspan.accessor.aligned.members"><span class="header-section-number">10.3</span> Members
[mdspan.accessor.aligned.members]<a href="#members-mdspan.accessor.aligned.members" class="self-link"></a></h2>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType, <span class="dt">size_t</span> other_byte_alignment<span class="op">&gt;</span></span>
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span>OtherElementType, other_byte_alignment<span class="op">&gt;)</span> <span class="kw">noexcept</span> <span class="op">{}</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Constraints</em>:
<code>is_convertible_v&lt;OtherElementType(*)[], element_type(*)[]&gt;</code>
is <code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates</em>:
<code>gcd(other_byte_alignment, byte_alignment) == byte_alignment</code>
is <code>true</code>.</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType<span class="op">&gt;</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span> <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a>    default_accessor<span class="op">&lt;</span>OtherElementType<span class="op">&gt;)</span> <span class="kw">noexcept</span> <span class="op">{}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints</em>:
<code>is_convertible_v&lt;OtherElementType(*)[], element_type(*)[]&gt;</code>
is <code>true</code>.</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> reference</span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>  access<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Preconditions</em>: <code>p</code> points to an object
<code>X</code> of a type similar (<strong>[conv.qual]</strong>) to
<code>element_type</code>, where <code>X</code> has alignment
<code>byte_alignment</code> (<strong>[basic.align]</strong>).</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects</em>: Equivalent to:
<code>return assume_aligned&lt;byte_alignment&gt;(p)[i];</code></p>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">typename</span> offset_policy<span class="op">::</span>data_handle_type</span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a>  offset<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Preconditions</em>: <code>p</code> points to an object
<code>X</code> of a type similar (<strong>[conv.qual]</strong>) to
<code>element_type</code>, where <code>X</code> has alignment
<code>byte_alignment</code> (<strong>[basic.align]</strong>).</p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects</em>: Equivalent to: <code>return p + i;</code></p>
<p>[<em>Example:</em> The following function <code>compute</code> uses
<code>is_sufficiently_aligned</code> to check whether a given
<code>mdspan</code> with <code>default_accessor</code> has a data handle
with sufficient alignment to be used with
<code>aligned_accessor&lt;float, 4 * sizeof(float)&gt;</code>. If so,
the function dispatches to a function
<code>compute_using_fourfold_overalignment</code> that requires fourfold
overalignment of arrays, but can therefore use hardware-specific
instructions, such as four-wide SIMD (Single Instruction Multiple Data)
instructions. Otherwise, <code>compute</code> dispatches to a possibly
less optimized function
<code>compute_without_requiring_overalignment</code> that has no
overalignment requirement.</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>compute_using_fourfold_overalignment<span class="op">(</span></span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_right,</span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">4</span> <span class="op">*</span> <span class="kw">alignof</span><span class="op">(</span><span class="dt">float</span><span class="op">)&gt;&gt;</span> x<span class="op">)</span>;</span>
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span></span>
<span id="cb35-7"><a href="#cb35-7" aria-hidden="true" tabindex="-1"></a>compute_without_requiring_overalignment<span class="op">(</span></span>
<span id="cb35-8"><a href="#cb35-8" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_right<span class="op">&gt;</span> x<span class="op">)</span>;</span>
<span id="cb35-9"><a href="#cb35-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-10"><a href="#cb35-10" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> compute<span class="op">(</span>std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;&gt;</span> x<span class="op">)</span></span>
<span id="cb35-11"><a href="#cb35-11" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb35-12"><a href="#cb35-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> byte_alignment <span class="op">=</span> <span class="dv">4</span> <span class="op">*</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">float</span><span class="op">)</span>; </span>
<span id="cb35-13"><a href="#cb35-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> accessor <span class="op">=</span></span>
<span id="cb35-14"><a href="#cb35-14" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;{}</span>;</span>
<span id="cb35-15"><a href="#cb35-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_handle <span class="op">=</span> x<span class="op">.</span>data_handle<span class="op">()</span>;</span>
<span id="cb35-16"><a href="#cb35-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-17"><a href="#cb35-17" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>std<span class="op">::</span>is_sufficiently_aligned<span class="op">&lt;</span>byte_alignment<span class="op">&gt;(</span>x_handle<span class="op">))</span> <span class="op">{</span></span>
<span id="cb35-18"><a href="#cb35-18" aria-hidden="true" tabindex="-1"></a>    compute_using_fourfold_overalignment<span class="op">(</span></span>
<span id="cb35-19"><a href="#cb35-19" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>mdspan<span class="op">{</span>x_handle, x<span class="op">.</span>mapping<span class="op">()</span>, accessor<span class="op">})</span>;</span>
<span id="cb35-20"><a href="#cb35-20" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb35-21"><a href="#cb35-21" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb35-22"><a href="#cb35-22" aria-hidden="true" tabindex="-1"></a>    compute_without_requiring_overalignment<span class="op">(</span>x<span class="op">)</span>;</span>
<span id="cb35-23"><a href="#cb35-23" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb35-24"><a href="#cb35-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<p>[<em>Example:</em> The following example shows how users can fulfill
the preconditions of <code>aligned_accessor</code> by using existing C++
Standard Library functionality to create overaligned allocations. The
example’s <code>allocate_overaligned</code> function uses
<code>aligned_alloc</code> to create an overaligned allocation.</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> delete_with_free <span class="op">{</span></span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> <span class="kw">operator</span><span class="op">()(</span>ElementType<span class="op">*</span> p<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>free<span class="op">(</span>p<span class="op">)</span>;</span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> allocation <span class="op">=</span> std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>ElementType<span class="op">[]</span>, delete_with_free<span class="op">&lt;</span>ElementType<span class="op">&gt;&gt;</span>;</span>
<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb36-12"><a href="#cb36-12" aria-hidden="true" tabindex="-1"></a>allocation<span class="op">&lt;</span>ElementType<span class="op">&gt;</span></span>
<span id="cb36-13"><a href="#cb36-13" aria-hidden="true" tabindex="-1"></a>  allocate_overaligned<span class="op">(</span><span class="kw">const</span> <span class="dt">size_t</span> num_elements<span class="op">)</span></span>
<span id="cb36-14"><a href="#cb36-14" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb36-15"><a href="#cb36-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> <span class="dt">size_t</span> num_bytes <span class="op">=</span> num_elements <span class="op">*</span> <span class="kw">sizeof</span><span class="op">(</span>ElementType<span class="op">)</span>;</span>
<span id="cb36-16"><a href="#cb36-16" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span><span class="op">*</span> ptr <span class="op">=</span> std<span class="op">::</span>aligned_alloc<span class="op">(</span>byte_alignment, num_bytes<span class="op">)</span>;</span>
<span id="cb36-17"><a href="#cb36-17" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">{</span>ptr, delete_with_free<span class="op">&lt;</span>ElementType<span class="op">&gt;{}}</span>;</span>
<span id="cb36-18"><a href="#cb36-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The example’s functions <code>vectorized_axpy</code> and
<code>vectorized_norm</code> require their input arrays to have 32-byte
alignment.</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span></span>
<span id="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span>, <span class="dt">int</span><span class="op">&gt;</span>,</span>
<span id="cb37-4"><a href="#cb37-4" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>layout_right,</span>
<span id="cb37-5"><a href="#cb37-5" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb37-6"><a href="#cb37-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb37-7"><a href="#cb37-7" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span> vectorized_axpy<span class="op">(</span></span>
<span id="cb37-8"><a href="#cb37-8" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y, <span class="dt">float</span> alpha, aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> x<span class="op">)</span>;</span>
<span id="cb37-9"><a href="#cb37-9" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">float</span> vectorized_norm<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y<span class="op">)</span>;</span></code></pre></div>
<p>The user’s function <code>user_function</code> would begin by
allocating “raw” overaligned arrays with
<code>allocate_overaligned</code>. It would then create aligned
<code>mdspan</code> with them, and pass the resulting
<code>mdspan</code> into the library’s functions.</p>
<div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> user_function<span class="op">(</span><span class="dt">size_t</span> num_elements, <span class="dt">float</span> alpha<span class="op">)</span></span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb38-3"><a href="#cb38-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">size_t</span> max_byte_alignment <span class="op">=</span> <span class="dv">32</span>;</span>
<span id="cb38-4"><a href="#cb38-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_alloc <span class="op">=</span></span>
<span id="cb38-5"><a href="#cb38-5" aria-hidden="true" tabindex="-1"></a>    allocate_overaligned<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb38-6"><a href="#cb38-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> y_alloc <span class="op">=</span></span>
<span id="cb38-7"><a href="#cb38-7" aria-hidden="true" tabindex="-1"></a>    allocate_overaligned<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb38-8"><a href="#cb38-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-9"><a href="#cb38-9" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> x<span class="op">(</span>x_alloc<span class="op">.</span>get<span class="op">())</span>;</span>
<span id="cb38-10"><a href="#cb38-10" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> y<span class="op">(</span>y_alloc<span class="op">.</span>get<span class="op">())</span>;</span>
<span id="cb38-11"><a href="#cb38-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-12"><a href="#cb38-12" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... fill the elements of x and y ...</span></span>
<span id="cb38-13"><a href="#cb38-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb38-14"><a href="#cb38-14" aria-hidden="true" tabindex="-1"></a>  vectorized_axpy<span class="op">(</span>y, alpha, x<span class="op">)</span>;</span>
<span id="cb38-15"><a href="#cb38-15" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> vectorized_norm<span class="op">(</span>y<span class="op">)</span>;</span>
<span id="cb38-16"><a href="#cb38-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<h1 data-number="11" id="appendix-a-detectably_invalid-nonmember-function-example"><span class="header-section-number">11</span> Appendix A:
<code>detectably_invalid</code> nonmember function example<a href="#appendix-a-detectably_invalid-nonmember-function-example" class="self-link"></a></h1>
<p>This section is nonnormative. This is the full source code with tests
for the <code>detectably_invalid</code> nonmember function example
above. Please see this
<a href="https://godbolt.org/z/4P9MGbhdj">Compiler Explorer link</a> for
a test with five different compilers: GCC 14.1, Clang 18.1.0, MSVC
v19.40 (VS17.10), and nvc++ 24.5.</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cassert&gt;</span></span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;concepts&gt;</span></span>
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cstdint&gt;</span></span>
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;stdexcept&gt;</span></span>
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;utility&gt;</span></span>
<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> has_detectably_invalid <span class="op">=</span> <span class="kw">requires</span><span class="op">(</span>Accessor acc<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type;</span>
<span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span> std<span class="op">::</span>as_const<span class="op">(</span>acc<span class="op">).</span>detectably_invalid<span class="op">(</span></span>
<span id="cb39-13"><a href="#cb39-13" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>declval<span class="op">&lt;</span><span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type<span class="op">&gt;()</span>,</span>
<span id="cb39-14"><a href="#cb39-14" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>declval<span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span><span class="op">&gt;()</span></span>
<span id="cb39-15"><a href="#cb39-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">)</span> <span class="op">}</span> <span class="kw">noexcept</span> <span class="op">-&gt;</span> std<span class="op">::</span>convertible_to<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span>;</span>
<span id="cb39-16"><a href="#cb39-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-17"><a href="#cb39-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-18"><a href="#cb39-18" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb39-19"><a href="#cb39-19" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> detectably_invalid<span class="op">(</span>Accessor<span class="op">&amp;&amp;</span> accessor,</span>
<span id="cb39-20"><a href="#cb39-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>Accessor<span class="op">&gt;::</span>data_handle_type handle,</span>
<span id="cb39-21"><a href="#cb39-21" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span></span>
<span id="cb39-22"><a href="#cb39-22" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb39-23"><a href="#cb39-23" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>has_detectably_invalid<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>Accessor<span class="op">&gt;&gt;)</span> <span class="op">{</span></span>
<span id="cb39-24"><a href="#cb39-24" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>as_const<span class="op">(</span>accessor<span class="op">).</span>detectably_invalid<span class="op">(</span>handle, size<span class="op">)</span>;</span>
<span id="cb39-25"><a href="#cb39-25" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-26"><a href="#cb39-26" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb39-27"><a href="#cb39-27" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb39-28"><a href="#cb39-28" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-29"><a href="#cb39-29" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb39-30"><a href="#cb39-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-31"><a href="#cb39-31" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> A <span class="op">{</span></span>
<span id="cb39-32"><a href="#cb39-32" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> <span class="dt">float</span><span class="op">*</span>;</span>
<span id="cb39-33"><a href="#cb39-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-34"><a href="#cb39-34" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type ptr, std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb39-35"><a href="#cb39-35" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> ptr <span class="op">==</span> <span class="kw">nullptr</span> <span class="op">&amp;&amp;</span> size <span class="op">!=</span> <span class="dv">0</span>;</span>
<span id="cb39-36"><a href="#cb39-36" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-37"><a href="#cb39-37" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-38"><a href="#cb39-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-39"><a href="#cb39-39" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> B <span class="op">{</span></span>
<span id="cb39-40"><a href="#cb39-40" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> <span class="dt">float</span><span class="op">*</span>;</span>
<span id="cb39-41"><a href="#cb39-41" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-42"><a href="#cb39-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-43"><a href="#cb39-43" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> C <span class="op">{</span></span>
<span id="cb39-44"><a href="#cb39-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> <span class="dt">float</span><span class="op">*</span>;</span>
<span id="cb39-45"><a href="#cb39-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-46"><a href="#cb39-46" aria-hidden="true" tabindex="-1"></a>  <span class="co">// This is nonconst, so it&#39;s not actually called.</span></span>
<span id="cb39-47"><a href="#cb39-47" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type ptr, std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-48"><a href="#cb39-48" aria-hidden="true" tabindex="-1"></a>    <span class="cf">throw</span> std<span class="op">::</span>runtime_error<span class="op">(</span><span class="st">&quot;C::detectably_invalid: uh oh&quot;</span><span class="op">)</span>;</span>
<span id="cb39-49"><a href="#cb39-49" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-50"><a href="#cb39-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-51"><a href="#cb39-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-52"><a href="#cb39-52" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> D <span class="op">{</span></span>
<span id="cb39-53"><a href="#cb39-53" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> <span class="dt">float</span><span class="op">*</span>;</span>
<span id="cb39-54"><a href="#cb39-54" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-55"><a href="#cb39-55" aria-hidden="true" tabindex="-1"></a>  <span class="co">// This is const but not noexcept, so it&#39;s not actually called.</span></span>
<span id="cb39-56"><a href="#cb39-56" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type ptr, std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb39-57"><a href="#cb39-57" aria-hidden="true" tabindex="-1"></a>    <span class="cf">throw</span> std<span class="op">::</span>runtime_error<span class="op">(</span><span class="st">&quot;D::detectably_invalid: uh oh&quot;</span><span class="op">)</span>;</span>
<span id="cb39-58"><a href="#cb39-58" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-59"><a href="#cb39-59" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-60"><a href="#cb39-60" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-61"><a href="#cb39-61" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-62"><a href="#cb39-62" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span></span>
<span id="cb39-63"><a href="#cb39-63" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb39-64"><a href="#cb39-64" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span><span class="op">*</span> ptr <span class="op">=</span> <span class="kw">nullptr</span>;</span>
<span id="cb39-65"><a href="#cb39-65" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-66"><a href="#cb39-66" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>A<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-67"><a href="#cb39-67" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>detectably_invalid<span class="op">(</span>A<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-68"><a href="#cb39-68" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-69"><a href="#cb39-69" aria-hidden="true" tabindex="-1"></a>  A a<span class="op">{}</span>;</span>
<span id="cb39-70"><a href="#cb39-70" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>a, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-71"><a href="#cb39-71" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>detectably_invalid<span class="op">(</span>a, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-72"><a href="#cb39-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-73"><a href="#cb39-73" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> A a_c<span class="op">{}</span>;</span>
<span id="cb39-74"><a href="#cb39-74" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>a_c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-75"><a href="#cb39-75" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>detectably_invalid<span class="op">(</span>a_c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-76"><a href="#cb39-76" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-77"><a href="#cb39-77" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>B<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-78"><a href="#cb39-78" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>B<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-79"><a href="#cb39-79" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-80"><a href="#cb39-80" aria-hidden="true" tabindex="-1"></a>  <span class="co">// B doesn&#39;t know how to check pointer validity.</span></span>
<span id="cb39-81"><a href="#cb39-81" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-82"><a href="#cb39-82" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>B<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-83"><a href="#cb39-83" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>B<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-84"><a href="#cb39-84" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-85"><a href="#cb39-85" aria-hidden="true" tabindex="-1"></a>  B b<span class="op">{}</span>;</span>
<span id="cb39-86"><a href="#cb39-86" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>b, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-87"><a href="#cb39-87" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>b, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-88"><a href="#cb39-88" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-89"><a href="#cb39-89" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> B b_c<span class="op">{}</span>;</span>
<span id="cb39-90"><a href="#cb39-90" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>b_c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-91"><a href="#cb39-91" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>b_c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-92"><a href="#cb39-92" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-93"><a href="#cb39-93" aria-hidden="true" tabindex="-1"></a>  <span class="co">// If users make detectably_invalid nonconst or not noexcept,</span></span>
<span id="cb39-94"><a href="#cb39-94" aria-hidden="true" tabindex="-1"></a>  <span class="co">// the nonmember function falls back to a default implementation.</span></span>
<span id="cb39-95"><a href="#cb39-95" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-96"><a href="#cb39-96" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-97"><a href="#cb39-97" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>C<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-98"><a href="#cb39-98" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>C<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-99"><a href="#cb39-99" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-100"><a href="#cb39-100" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-101"><a href="#cb39-101" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;C{} threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<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="cb39-102"><a href="#cb39-102" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-103"><a href="#cb39-103" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-104"><a href="#cb39-104" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-105"><a href="#cb39-105" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> C c_c<span class="op">{}</span>;</span>
<span id="cb39-106"><a href="#cb39-106" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>c_c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-107"><a href="#cb39-107" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>c_c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-108"><a href="#cb39-108" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-109"><a href="#cb39-109" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-110"><a href="#cb39-110" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;const C threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<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="cb39-111"><a href="#cb39-111" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-112"><a href="#cb39-112" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-113"><a href="#cb39-113" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-114"><a href="#cb39-114" aria-hidden="true" tabindex="-1"></a>    C c<span class="op">{}</span>;</span>
<span id="cb39-115"><a href="#cb39-115" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-116"><a href="#cb39-116" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-117"><a href="#cb39-117" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-118"><a href="#cb39-118" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-119"><a href="#cb39-119" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;nonconst C threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<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="cb39-120"><a href="#cb39-120" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-121"><a href="#cb39-121" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-122"><a href="#cb39-122" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-123"><a href="#cb39-123" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>D<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-124"><a href="#cb39-124" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>D<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-125"><a href="#cb39-125" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-126"><a href="#cb39-126" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-127"><a href="#cb39-127" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;D{} threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<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="cb39-128"><a href="#cb39-128" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-129"><a href="#cb39-129" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-130"><a href="#cb39-130" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-131"><a href="#cb39-131" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> D d_c<span class="op">{}</span>;</span>
<span id="cb39-132"><a href="#cb39-132" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>d_c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-133"><a href="#cb39-133" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>d_c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-134"><a href="#cb39-134" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-135"><a href="#cb39-135" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-136"><a href="#cb39-136" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;const D threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<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="cb39-137"><a href="#cb39-137" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-138"><a href="#cb39-138" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-139"><a href="#cb39-139" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-140"><a href="#cb39-140" aria-hidden="true" tabindex="-1"></a>    D d<span class="op">{}</span>;</span>
<span id="cb39-141"><a href="#cb39-141" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>d, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-142"><a href="#cb39-142" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>d, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-143"><a href="#cb39-143" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-144"><a href="#cb39-144" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-145"><a href="#cb39-145" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;nonconst D threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<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="cb39-146"><a href="#cb39-146" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-147"><a href="#cb39-147" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-148"><a href="#cb39-148" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;Made it to the end</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb39-149"><a href="#cb39-149" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb39-150"><a href="#cb39-150" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="12" id="appendix-b-implementation-and-demo"><span class="header-section-number">12</span> Appendix B: Implementation and
demo<a href="#appendix-b-implementation-and-demo" class="self-link"></a></h1>
<p><a href="https://godbolt.org/z/3z1WaW778">This Compiler Explorer
link</a> gives a full implementation of <code>aligned_accessor</code>
and a demonstration. We show the full source code from that link here
below.</p>
<div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;https://raw.githubusercontent.com/kokkos/mdspan/single-header/mdspan.hpp&gt;</span></span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;bit&gt;</span></span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cassert&gt;</span></span>
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cmath&gt;</span></span>
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a><span class="pp">#if defined(_MSC_VER)</span></span>
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#  include </span><span class="im">&lt;cstdlib&gt;</span><span class="pp"> </span><span class="co">// MSVC&#39;s _aligned_malloc</span></span>
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a><span class="pp">#endif</span></span>
<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;exception&gt;</span></span>
<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;functional&gt;</span></span>
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;memory&gt;</span></span>
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;numeric&gt;</span></span>
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> stdex <span class="op">=</span> std<span class="op">::</span>experimental;</span>
<span id="cb40-15"><a href="#cb40-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-16"><a href="#cb40-16" aria-hidden="true" tabindex="-1"></a><span class="co">// P2389 (voted into C++ at June 2024 STL plenary)</span></span>
<span id="cb40-17"><a href="#cb40-17" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb40-18"><a href="#cb40-18" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> Rank, <span class="kw">class</span> IndexType <span class="op">=</span> <span class="dt">size_t</span><span class="op">&gt;</span></span>
<span id="cb40-19"><a href="#cb40-19" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> dims <span class="op">=</span> dextents<span class="op">&lt;</span>IndexType, Rank<span class="op">&gt;</span>;</span>
<span id="cb40-20"><a href="#cb40-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-21"><a href="#cb40-21" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb40-22"><a href="#cb40-22" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> is_sufficiently_aligned<span class="op">(</span>ElementType<span class="op">*</span> p<span class="op">)</span></span>
<span id="cb40-23"><a href="#cb40-23" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-24"><a href="#cb40-24" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> bit_cast<span class="op">&lt;</span><span class="dt">uintptr_t</span><span class="op">&gt;(</span>p<span class="op">)</span> <span class="op">%</span> byte_alignment <span class="op">==</span> <span class="dv">0</span>;</span>
<span id="cb40-25"><a href="#cb40-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-26"><a href="#cb40-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-27"><a href="#cb40-27" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb40-28"><a href="#cb40-28" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> aligned_accessor <span class="op">{</span></span>
<span id="cb40-29"><a href="#cb40-29" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb40-30"><a href="#cb40-30" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>has_single_bit<span class="op">(</span>byte_alignment<span class="op">)</span>,</span>
<span id="cb40-31"><a href="#cb40-31" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;byte_alignment must be a power of two.&quot;</span><span class="op">)</span>;</span>
<span id="cb40-32"><a href="#cb40-32" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>byte_alignment <span class="op">&gt;=</span> <span class="kw">alignof</span><span class="op">(</span>ElementType<span class="op">)</span>,</span>
<span id="cb40-33"><a href="#cb40-33" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;Insufficient byte alignment for ElementType&quot;</span><span class="op">)</span>;</span>
<span id="cb40-34"><a href="#cb40-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-35"><a href="#cb40-35" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> offset_policy <span class="op">=</span> stdex<span class="op">::</span>default_accessor<span class="op">&lt;</span>ElementType<span class="op">&gt;</span>;</span>
<span id="cb40-36"><a href="#cb40-36" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> element_type <span class="op">=</span> ElementType;</span>
<span id="cb40-37"><a href="#cb40-37" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> reference <span class="op">=</span> ElementType<span class="op">&amp;</span>;</span>
<span id="cb40-38"><a href="#cb40-38" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> ElementType<span class="op">*</span>;</span>
<span id="cb40-39"><a href="#cb40-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-40"><a href="#cb40-40" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> aligned_accessor<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb40-41"><a href="#cb40-41" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-42"><a href="#cb40-42" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span></span>
<span id="cb40-43"><a href="#cb40-43" aria-hidden="true" tabindex="-1"></a>    <span class="kw">class</span> OtherElementType,</span>
<span id="cb40-44"><a href="#cb40-44" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> other_byte_alignment<span class="op">&gt;</span></span>
<span id="cb40-45"><a href="#cb40-45" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span>is_convertible_v<span class="op">&lt;</span></span>
<span id="cb40-46"><a href="#cb40-46" aria-hidden="true" tabindex="-1"></a>    OtherElementType<span class="op">(*)[]</span>, element_type<span class="op">(*)[]&gt;)</span></span>
<span id="cb40-47"><a href="#cb40-47" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb40-48"><a href="#cb40-48" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span>OtherElementType, other_byte_alignment<span class="op">&gt;)</span></span>
<span id="cb40-49"><a href="#cb40-49" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span></span>
<span id="cb40-50"><a href="#cb40-50" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb40-51"><a href="#cb40-51" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">size_t</span> the_gcd <span class="op">=</span></span>
<span id="cb40-52"><a href="#cb40-52" aria-hidden="true" tabindex="-1"></a>      gcd<span class="op">(</span>other_byte_alignment, byte_alignment<span class="op">)</span>;</span>
<span id="cb40-53"><a href="#cb40-53" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>the_gcd <span class="op">==</span> byte_alignment<span class="op">)</span>;</span>
<span id="cb40-54"><a href="#cb40-54" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-55"><a href="#cb40-55" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-56"><a href="#cb40-56" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType<span class="op">&gt;</span></span>
<span id="cb40-57"><a href="#cb40-57" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span>is_convertible_v<span class="op">&lt;</span></span>
<span id="cb40-58"><a href="#cb40-58" aria-hidden="true" tabindex="-1"></a>    OtherElementType<span class="op">(*)[]</span>, element_type<span class="op">(*)[]&gt;)</span></span>
<span id="cb40-59"><a href="#cb40-59" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span> aligned_accessor<span class="op">(</span></span>
<span id="cb40-60"><a href="#cb40-60" aria-hidden="true" tabindex="-1"></a>    stdex<span class="op">::</span>default_accessor<span class="op">&lt;</span>OtherElementType<span class="op">&gt;)</span> <span class="kw">noexcept</span></span>
<span id="cb40-61"><a href="#cb40-61" aria-hidden="true" tabindex="-1"></a>  <span class="op">{}</span></span>
<span id="cb40-62"><a href="#cb40-62" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb40-63"><a href="#cb40-63" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span></span>
<span id="cb40-64"><a href="#cb40-64" aria-hidden="true" tabindex="-1"></a>    <span class="kw">operator</span> stdex<span class="op">::</span>default_accessor<span class="op">&lt;</span>element_type<span class="op">&gt;()</span> <span class="kw">const</span></span>
<span id="cb40-65"><a href="#cb40-65" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb40-66"><a href="#cb40-66" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb40-67"><a href="#cb40-67" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-68"><a href="#cb40-68" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-69"><a href="#cb40-69" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> reference</span>
<span id="cb40-70"><a href="#cb40-70" aria-hidden="true" tabindex="-1"></a>    access<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span></span>
<span id="cb40-71"><a href="#cb40-71" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb40-72"><a href="#cb40-72" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> assume_aligned<span class="op">&lt;</span>byte_alignment<span class="op">&gt;(</span>p<span class="op">)[</span>i<span class="op">]</span>;</span>
<span id="cb40-73"><a href="#cb40-73" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-74"><a href="#cb40-74" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-75"><a href="#cb40-75" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">typename</span> offset_policy<span class="op">::</span>data_handle_type</span>
<span id="cb40-76"><a href="#cb40-76" aria-hidden="true" tabindex="-1"></a>  offset<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb40-77"><a href="#cb40-77" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> p <span class="op">+</span> i;</span>
<span id="cb40-78"><a href="#cb40-78" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-79"><a href="#cb40-79" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb40-80"><a href="#cb40-80" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-81"><a href="#cb40-81" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// namespace std</span></span>
<span id="cb40-82"><a href="#cb40-82" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-83"><a href="#cb40-83" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> <span class="op">{</span> <span class="co">// (anonymous)</span></span>
<span id="cb40-84"><a href="#cb40-84" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-85"><a href="#cb40-85" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb40-86"><a href="#cb40-86" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span></span>
<span id="cb40-87"><a href="#cb40-87" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span>, <span class="dt">int</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_right,</span>
<span id="cb40-88"><a href="#cb40-88" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb40-89"><a href="#cb40-89" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-90"><a href="#cb40-90" aria-hidden="true" tabindex="-1"></a><span class="co">// Interfaces that require 32-byte alignment,</span></span>
<span id="cb40-91"><a href="#cb40-91" aria-hidden="true" tabindex="-1"></a><span class="co">// because they want to do 8-wide SIMD of float.</span></span>
<span id="cb40-92"><a href="#cb40-92" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
<span id="cb40-93"><a href="#cb40-93" aria-hidden="true" tabindex="-1"></a>vectorized_axpby<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y,</span>
<span id="cb40-94"><a href="#cb40-94" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span> alpha, aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> x, <span class="dt">float</span> beta<span class="op">)</span></span>
<span id="cb40-95"><a href="#cb40-95" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-96"><a href="#cb40-96" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> y<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb40-97"><a href="#cb40-97" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-98"><a href="#cb40-98" aria-hidden="true" tabindex="-1"></a>    y<span class="op">[</span>k<span class="op">]</span> <span class="op">=</span> beta <span class="op">*</span> y<span class="op">[</span>k<span class="op">]</span> <span class="op">+</span> alpha <span class="op">*</span> x<span class="op">[</span>k<span class="op">]</span>; </span>
<span id="cb40-99"><a href="#cb40-99" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-100"><a href="#cb40-100" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-101"><a href="#cb40-101" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-102"><a href="#cb40-102" aria-hidden="true" tabindex="-1"></a><span class="co">// 1-norm of the vector y</span></span>
<span id="cb40-103"><a href="#cb40-103" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> vectorized_norm<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y<span class="op">)</span></span>
<span id="cb40-104"><a href="#cb40-104" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-105"><a href="#cb40-105" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span> one_norm <span class="op">=</span> <span class="fl">0.0</span><span class="bu">f</span>;</span>
<span id="cb40-106"><a href="#cb40-106" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> y<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-107"><a href="#cb40-107" aria-hidden="true" tabindex="-1"></a>    one_norm <span class="op">+=</span> std<span class="op">::</span>fabs<span class="op">(</span>y<span class="op">[</span>k<span class="op">])</span>; </span>
<span id="cb40-108"><a href="#cb40-108" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-109"><a href="#cb40-109" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> one_norm;</span>
<span id="cb40-110"><a href="#cb40-110" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-111"><a href="#cb40-111" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-112"><a href="#cb40-112" aria-hidden="true" tabindex="-1"></a><span class="co">// Interfaces that require 16-byte alignment,</span></span>
<span id="cb40-113"><a href="#cb40-113" aria-hidden="true" tabindex="-1"></a><span class="co">// because they want to do 4-wide SIMD of float.</span></span>
<span id="cb40-114"><a href="#cb40-114" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> fill_x<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">16</span><span class="op">&gt;</span> x<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-115"><a href="#cb40-115" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-116"><a href="#cb40-116" aria-hidden="true" tabindex="-1"></a>    x<span class="op">[</span>k<span class="op">]</span> <span class="op">=</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;(</span>k <span class="op">+</span> <span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb40-117"><a href="#cb40-117" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>  </span>
<span id="cb40-118"><a href="#cb40-118" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-119"><a href="#cb40-119" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> fill_y<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">16</span><span class="op">&gt;</span> y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-120"><a href="#cb40-120" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> y<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-121"><a href="#cb40-121" aria-hidden="true" tabindex="-1"></a>    y<span class="op">[</span>k<span class="op">]</span> <span class="op">=</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;(</span>k <span class="op">-</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb40-122"><a href="#cb40-122" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>  </span>
<span id="cb40-123"><a href="#cb40-123" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-124"><a href="#cb40-124" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-125"><a href="#cb40-125" aria-hidden="true" tabindex="-1"></a><span class="co">// Helper functions for making overaligned array allocations.</span></span>
<span id="cb40-126"><a href="#cb40-126" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-127"><a href="#cb40-127" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb40-128"><a href="#cb40-128" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> delete_raw <span class="op">{</span></span>
<span id="cb40-129"><a href="#cb40-129" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> <span class="kw">operator</span><span class="op">()(</span>ElementType<span class="op">*</span> p<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb40-130"><a href="#cb40-130" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>free<span class="op">(</span>p<span class="op">)</span>;</span>
<span id="cb40-131"><a href="#cb40-131" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-132"><a href="#cb40-132" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb40-133"><a href="#cb40-133" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-134"><a href="#cb40-134" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb40-135"><a href="#cb40-135" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> allocation <span class="op">=</span></span>
<span id="cb40-136"><a href="#cb40-136" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>ElementType<span class="op">[]</span>, delete_raw<span class="op">&lt;</span>ElementType<span class="op">&gt;&gt;</span>;</span>
<span id="cb40-137"><a href="#cb40-137" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-138"><a href="#cb40-138" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, std<span class="op">::</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb40-139"><a href="#cb40-139" aria-hidden="true" tabindex="-1"></a>allocation<span class="op">&lt;</span>ElementType<span class="op">&gt;</span> allocate_raw<span class="op">(</span><span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> num_elements<span class="op">)</span></span>
<span id="cb40-140"><a href="#cb40-140" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-141"><a href="#cb40-141" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> num_bytes <span class="op">=</span> num_elements <span class="op">*</span> <span class="kw">sizeof</span><span class="op">(</span>ElementType<span class="op">)</span>;</span>
<span id="cb40-142"><a href="#cb40-142" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span><span class="op">*</span> ptr <span class="op">=</span> <span class="kw">reinterpret_cast</span><span class="op">&lt;</span><span class="dt">float</span><span class="op">*&gt;(</span></span>
<span id="cb40-143"><a href="#cb40-143" aria-hidden="true" tabindex="-1"></a><span class="pp">#if defined(_MSC_VER)</span></span>
<span id="cb40-144"><a href="#cb40-144" aria-hidden="true" tabindex="-1"></a>    _aligned_malloc<span class="op">(</span>byte_alignment, num_bytes<span class="op">)</span></span>
<span id="cb40-145"><a href="#cb40-145" aria-hidden="true" tabindex="-1"></a><span class="pp">#else</span></span>
<span id="cb40-146"><a href="#cb40-146" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>aligned_alloc<span class="op">(</span>byte_alignment, num_bytes<span class="op">)</span></span>
<span id="cb40-147"><a href="#cb40-147" aria-hidden="true" tabindex="-1"></a><span class="pp">#endif</span></span>
<span id="cb40-148"><a href="#cb40-148" aria-hidden="true" tabindex="-1"></a>  <span class="op">)</span>;</span>
<span id="cb40-149"><a href="#cb40-149" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">{</span>ptr, delete_raw<span class="op">&lt;</span>ElementType<span class="op">&gt;{}}</span>;</span>
<span id="cb40-150"><a href="#cb40-150" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-151"><a href="#cb40-151" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-152"><a href="#cb40-152" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> user_function<span class="op">(</span><span class="dt">size_t</span> num_elements, <span class="dt">float</span> alpha, <span class="dt">float</span> beta<span class="op">)</span></span>
<span id="cb40-153"><a href="#cb40-153" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-154"><a href="#cb40-154" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">size_t</span> max_byte_alignment <span class="op">=</span> <span class="dv">32</span>;</span>
<span id="cb40-155"><a href="#cb40-155" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_alloc <span class="op">=</span> allocate_raw<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb40-156"><a href="#cb40-156" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> y_alloc <span class="op">=</span> allocate_raw<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb40-157"><a href="#cb40-157" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-158"><a href="#cb40-158" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> x<span class="op">(</span>x_alloc<span class="op">.</span>get<span class="op">()</span>, num_elements<span class="op">)</span>;</span>
<span id="cb40-159"><a href="#cb40-159" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> y<span class="op">(</span>y_alloc<span class="op">.</span>get<span class="op">()</span>, num_elements<span class="op">)</span>;</span>
<span id="cb40-160"><a href="#cb40-160" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-161"><a href="#cb40-161" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Implicit conversion from 32-byte aligned to 16-byte aligned</span></span>
<span id="cb40-162"><a href="#cb40-162" aria-hidden="true" tabindex="-1"></a>  fill_x<span class="op">(</span>x<span class="op">)</span>;</span>
<span id="cb40-163"><a href="#cb40-163" aria-hidden="true" tabindex="-1"></a>  fill_y<span class="op">(</span>y<span class="op">)</span>;</span>
<span id="cb40-164"><a href="#cb40-164" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-165"><a href="#cb40-165" aria-hidden="true" tabindex="-1"></a>  <span class="co">// No conversion: interfaces expect 32-byte aligned and get it</span></span>
<span id="cb40-166"><a href="#cb40-166" aria-hidden="true" tabindex="-1"></a>  vectorized_axpby<span class="op">(</span>y, alpha, x, beta<span class="op">)</span>;</span>
<span id="cb40-167"><a href="#cb40-167" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> vectorized_norm<span class="op">(</span>y<span class="op">)</span>;</span>
<span id="cb40-168"><a href="#cb40-168" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-169"><a href="#cb40-169" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-170"><a href="#cb40-170" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// namespace (anonymous)</span></span>
<span id="cb40-171"><a href="#cb40-171" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-172"><a href="#cb40-172" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">(</span><span class="dt">int</span> argc, <span class="dt">char</span><span class="op">*</span> argv<span class="op">[])</span></span>
<span id="cb40-173"><a href="#cb40-173" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-174"><a href="#cb40-174" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span> result <span class="op">=</span> user_function<span class="op">(</span><span class="dv">10</span>, <span class="fl">1.0</span><span class="bu">f</span>, <span class="op">-</span><span class="fl">1.0</span><span class="bu">f</span><span class="op">)</span>;</span>
<span id="cb40-175"><a href="#cb40-175" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>result <span class="op">==</span> <span class="fl">30.0</span><span class="bu">f</span><span class="op">)</span>; <span class="co">// 3 + 3 + ... + 3 = 30</span></span>
<span id="cb40-176"><a href="#cb40-176" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb40-177"><a href="#cb40-177" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
</div>
</body>
</html>
