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

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

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

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

code.sourceCode > span { display: inline; }
</style>
  <style type="text/css">a {
color : #4183C4;
text-decoration: underline;
}
a.marginalized {
text-decoration: none;
}
a.self-link {
text-decoration: none;
}
h1#toctitle {
border-bottom: 1px solid #cccccc;
}
#TOC li {
margin-top: 1px;
margin-bottom: 1px;
}
#TOC ul>li:before { display: none; }
h3.subtitle { margin-top: -15px; }
h1:target { background-color: transparent; }
h2:target { background-color: transparent; }
h3:target { background-color: transparent; }
h4:target { background-color: transparent; }
h5:target { background-color: transparent; }
h6:target { background-color: transparent; }
code span.co { font-family: monospace; }
table tr {
background-color: white;
}
table tr:nth-child(2n) {
background-color: #f6f8fa;
}
#title-block-header > table tr:nth-child(2n) {
background-color: white;
}
td > div.sourceCode {
background-color: inherit;
}
table {
border-collapse: collapse;
}
table td, table th {
border: 1px solid #cccccc;
}
table th {
border-bottom: 1px solid black;
text-align: center;
}
table tr:first-child th {
border-top: 0;
}
table tr:last-child td {
border-bottom: 0;
}
table tr td:first-child,
table tr th:first-child {
border-left: 0;
}
table tr td:last-child,
table tr th:last-child {
border-right: 0;
}
table tbody tr:first-child td {
border-top: 1px solid black;
}
#title-block-header td { border: 0; }
@media all {
body {
margin: 2em;
}
}
@media screen and (min-width: 480px) {
body {
margin: 5em;
}
}
#refs code{padding-left: 0px; text-indent: 0px;}
:root {
--diff-ins: #e6ffed;
--diff-strongins: #acf2bd;
--diff-del: #ffdddd;
--diff-strongdel: #ff8888;
}
span.diffins {
background-color: var(--diff-strongins);
}
span.diffdel {
background-color: var(--diff-strongdel);
}
div.rm { text-decoration: line-through; }
div.rm code.sourceCode { text-decoration: line-through; }
div.addu, span.addu {
color: #006e28;
background-color: var(--diff-ins);
}

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

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2747R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2022-12-16</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      EWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.com</a>&gt;<br>
    </td>
  </tr>
</table>

</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#introduction"><span class="toc-section-number">1</span> Introduction<span></span></a></li>
<li><a href="#type-erasure"><span class="toc-section-number">2</span> Type Erasure<span></span></a></li>
<li><a href="#placement-new"><span class="toc-section-number">3</span> Placement new<span></span></a></li>
<li><a href="#uninitialized-objects"><span class="toc-section-number">4</span> Uninitialized objects<span></span></a></li>
<li><a href="#proposal"><span class="toc-section-number">5</span> Proposal<span></span></a>
<ul>
<li><a href="#implementation-concerns"><span class="toc-section-number">5.1</span> Implementation Concerns<span></span></a></li>
</ul></li>
<li><a href="#bibliography"><span class="toc-section-number">6</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>One of the operations that you are not allowed to do during constant evaluation today is, from <a href="https://eel.is/c++draft/expr.const#5.14">[expr.const]/5.14</a>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">(5.14)</a></span> a conversion from type <code class="sourceCode cpp"><em>cv</em> <span class="dt">void</span><span class="op">*</span></code> to a pointer-to-object type;</p>
</blockquote>
<p>This makes some amount of sense from the perspective of wanting constant evaluation to be a safer subset of C++, we can’t just go throwing away all of our type information. But not all conversions from <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code> are the same - some are, in fact, perfectly safe, and the lack of ability to do so prevents some useful tools from being available at compile time.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="type-erasure"><span class="header-section-number">2</span> Type Erasure<a href="#type-erasure" class="self-link"></a></h1>
<p>Consider the following [very] reduced implementation of <code class="sourceCode cpp">function_ref</code>:</p>
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R, <span class="kw">typename</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">class</span> function_ref<span class="op">&lt;</span>R<span class="op">(</span>Args<span class="op">...)&gt;</span> <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>    <span class="dt">void</span><span class="op">*</span> data;</span>
<span id="cb1-4"><a href="#cb1-4"></a>    <span class="kw">auto</span> <span class="op">(*</span>func<span class="op">)(</span><span class="dt">void</span><span class="op">*</span>, Args<span class="op">...)</span> <span class="op">-&gt;</span> R;</span>
<span id="cb1-5"><a href="#cb1-5"></a></span>
<span id="cb1-6"><a href="#cb1-6"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb1-7"><a href="#cb1-7"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> F<span class="op">&gt;</span></span>
<span id="cb1-8"><a href="#cb1-8"></a>    <span class="kw">constexpr</span> function_ref<span class="op">(</span>F<span class="op">&amp;&amp;</span> f<span class="op">)</span></span>
<span id="cb1-9"><a href="#cb1-9"></a>      <span class="op">:</span> data<span class="op">(&amp;</span>f<span class="op">)</span></span>
<span id="cb1-10"><a href="#cb1-10"></a>      , func<span class="op">(+[](</span><span class="dt">void</span><span class="op">*</span> f, Args<span class="op">...</span> args<span class="op">){</span></span>
<span id="cb1-11"><a href="#cb1-11"></a>          <span class="kw">using</span> FD <span class="op">=</span> std<span class="op">::</span>remove_reference_t<span class="op">&lt;</span>F<span class="op">&gt;</span>;</span>
<span id="cb1-12"><a href="#cb1-12"></a>          <span class="cf">return</span> <span class="op">(*</span><span class="kw">static_cast</span><span class="op">&lt;</span>FD<span class="op">*&gt;(</span>f<span class="op">))(</span>args<span class="op">...)</span>;</span>
<span id="cb1-13"><a href="#cb1-13"></a>      <span class="op">})</span></span>
<span id="cb1-14"><a href="#cb1-14"></a>    <span class="op">{</span> <span class="op">}</span></span>
<span id="cb1-15"><a href="#cb1-15"></a></span>
<span id="cb1-16"><a href="#cb1-16"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">()(</span>Args<span class="op">...</span> args<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> R <span class="op">{</span></span>
<span id="cb1-17"><a href="#cb1-17"></a>        <span class="cf">return</span> func<span class="op">(</span>data, args<span class="op">...)</span>;</span>
<span id="cb1-18"><a href="#cb1-18"></a>    <span class="op">}</span></span>
<span id="cb1-19"><a href="#cb1-19"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>This is a common technique for type erasure - we have a <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code> that type erases some data and then we have a function pointer that knows how to cast that <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code> to the appropriate type. <code class="sourceCode cpp">data</code> here may be a <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code>, but it <em>actually does</em> point to an <code class="sourceCode cpp">FD</code>. That cast right there is perfectly safe, by construction. But we’re just not allowed to do it during constant evaluation time.</p>
<p>Which means that this entire implementation strategy just… doesn’t work.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="placement-new"><span class="header-section-number">3</span> Placement new<a href="#placement-new" class="self-link"></a></h1>
<p>Consider this implementation of <code class="sourceCode cpp">std<span class="op">::</span>uninitialized_copy</code>, partially adjusted from <a href="https://en.cppreference.com/w/cpp/memory/uninitialized_copy">cppreference</a>:</p>
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">template</span> <span class="op">&lt;</span>input_iterator I, sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span> S, nothrow_forward_iterator I2<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="kw">constexpr</span> <span class="kw">auto</span> uninitialized_copy<span class="op">(</span>I first, S last, I2 d_first<span class="op">)</span> <span class="op">-&gt;</span> I2 <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3"></a>    <span class="kw">using</span> T <span class="op">=</span> iter_value_t<span class="op">&lt;</span>I2<span class="op">&gt;</span>;</span>
<span id="cb2-4"><a href="#cb2-4"></a>    I2 current <span class="op">=</span> d_first;</span>
<span id="cb2-5"><a href="#cb2-5"></a>    <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb2-6"><a href="#cb2-6"></a>        <span class="cf">for</span> <span class="op">(</span>; first <span class="op">!=</span> last; <span class="op">++</span>first, <span class="op">(</span><span class="dt">void</span><span class="op">)++</span>current<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-7"><a href="#cb2-7"></a>            <span class="op">::</span><span class="kw">new</span> <span class="op">(</span>std<span class="op">::</span>addressof<span class="op">(*</span>current<span class="op">))</span> T<span class="op">(*</span>first<span class="op">)</span>;</span>
<span id="cb2-8"><a href="#cb2-8"></a>        <span class="op">}</span></span>
<span id="cb2-9"><a href="#cb2-9"></a>    <span class="op">}</span> <span class="cf">catch</span> <span class="op">(...)</span> <span class="op">{</span></span>
<span id="cb2-10"><a href="#cb2-10"></a>        std<span class="op">::</span>destroy<span class="op">(</span>d_first, current<span class="op">)</span>;</span>
<span id="cb2-11"><a href="#cb2-11"></a>        <span class="cf">throw</span>;</span>
<span id="cb2-12"><a href="#cb2-12"></a>    <span class="op">}</span></span>
<span id="cb2-13"><a href="#cb2-13"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This fails during constant evaluation today because placement new takes a <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code>. But it takes a <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code> that points to a <code class="sourceCode cpp">T</code> - we know that by construction. It’s just that we happen to lose that information along the way.</p>
<p>Moreover, that’s not <em>actually</em> how <code class="sourceCode cpp">uninitialized_copy</code> is specified, we actually do this:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb3"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb3-1"><a href="#cb3-1"></a><span class="st">- ::new (std::addressof(*current)) T(*first);</span></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="va">+ ::new (<em>voidify</em>(*current)) T(*first);</span></span></code></pre></div>
</div>
</blockquote>
<p>where:</p>
<blockquote>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2"></a>  <span class="kw">constexpr</span> <span class="dt">void</span><span class="op">*</span> <em>voidify</em><span class="op">(</span>T<span class="op">&amp;</span> obj<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3"></a>    <span class="cf">return</span> <span class="kw">const_cast</span><span class="op">&lt;</span><span class="dt">void</span><span class="op">*&gt;(</span><span class="kw">static_cast</span><span class="op">&lt;</span><span class="kw">const</span> <span class="kw">volatile</span> <span class="dt">void</span><span class="op">*&gt;(</span>std<span class="op">::</span>addressof<span class="op">(</span>obj<span class="op">)))</span>;</span>
<span id="cb4-4"><a href="#cb4-4"></a>  <span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Which exists to avoid users having written a global placement new that takes a <code class="sourceCode cpp">T<span class="op">*</span></code>.</p>
<p>The workaround, introduced by <span class="citation" data-cites="P0784R7">[<a href="#ref-P0784R7" role="doc-biblioref">P0784R7</a>]</span>, is a new library function:</p>
<blockquote>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="kw">constexpr</span> T<span class="op">*</span> construct_at<span class="op">(</span> T<span class="op">*</span> p, Args<span class="op">&amp;&amp;...</span> args <span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>This is a magic library function that is specified to do the same <code class="sourceCode cpp"><em>voidify</em></code> dance, but which the language simply recognizes as an allowed thing to do. <code class="sourceCode cpp">std<span class="op">::</span>construct_at</code> is explicitly allowed in <a href="https://eel.is/c++draft/expr.const">[expr.const]/6</a>:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">6</a></span> […] Similarly, the evaluation of a call to <code class="sourceCode cpp">std​<span class="op">::</span>​construct_­at</code> or <code class="sourceCode cpp">std​<span class="op">::</span>​ranges​<span class="op">::</span>​construct_­at</code> ([specialized.construct]) does not disqualify <code class="sourceCode cpp">E</code> from being a core constant expression unless the first argument, of type <code class="sourceCode cpp">T<span class="op">*</span></code>, does not point to storage allocated with <code class="sourceCode cpp">std​<span class="op">::</span>​allocator<span class="op">&lt;</span>T<span class="op">&gt;</span></code> or to an object whose lifetime began within the evaluation of <code class="sourceCode cpp">E</code>, or the evaluation of the underlying constructor call disqualifies <code class="sourceCode cpp">E</code> from being a core constant expression.</p>
</blockquote>
<p>It’s good that we actually have a solution - we can make <code class="sourceCode cpp">uninitialized_copy</code> usable during constant evaluation simply by using <code class="sourceCode cpp">std<span class="op">::</span>construct_at</code>. There’s even a paper to do so (<span class="citation" data-cites="P2283R2">[<a href="#ref-P2283R2" role="doc-biblioref">P2283R2</a>]</span>). But that paper also had hinted at a larger problem: <code class="sourceCode cpp">std<span class="op">::</span>construct_at</code> is an <em>extremely</em> limited tool as compared to placement new.</p>
<p>Consider the different kinds of initialization we have in C++:</p>
<table>
<colgroup>
<col style="width: 20%"></col>
<col style="width: 20%"></col>
<col style="width: 60%"></col>
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>kind</strong>
</div></th>
<th><div style="text-align:center">
<strong>placement new</strong>
</div></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp">std<span class="op">::</span>construct_at</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>value initialization</td>
<td><code class="sourceCode cpp"><span class="kw">new</span> <span class="op">(</span>p<span class="op">)</span> T<span class="op">(</span>args<span class="op">...)</span></code></td>
<td><code class="sourceCode cpp">std<span class="op">::</span>construct_at<span class="op">(</span>p, args<span class="op">...)</span></code></td>
</tr>
<tr class="even">
<td>default initialization</td>
<td><code class="sourceCode cpp"><span class="kw">new</span> <span class="op">(</span>p<span class="op">)</span> T</code></td>
<td>Not currently possible. <span class="citation" data-cites="P2283R1">[<a href="#ref-P2283R1" role="doc-biblioref">P2283R1</a>]</span> proposed <code class="sourceCode cpp">std<span class="op">::</span>default_construct_at</code></td>
</tr>
<tr class="odd">
<td>list initialization</td>
<td><code class="sourceCode cpp"><span class="kw">new</span> <span class="op">(</span>p<span class="op">)</span> T<span class="op">{</span>a, b<span class="op">}</span></code></td>
<td>Not currently possible, could be a new function?</td>
</tr>
<tr class="even">
<td>designated initialization</td>
<td><code class="sourceCode cpp"><span class="kw">new</span> <span class="op">(</span>p<span class="op">)</span> T<span class="op">{.</span>a<span class="op">=</span>a, <span class="op">.</span>b<span class="op">=</span>b<span class="op">}</span></code></td>
<td>Not possible to even write a function</td>
</tr>
</tbody>
</table>
<p>That’s already not a great outlook for <code class="sourceCode cpp">std<span class="op">::</span>construct_at</code>, but for use-cases like <code class="sourceCode cpp">uninitialized_copy</code>, we have to also consider the case of guaranteed copy elision:</p>
<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">auto</span> get_object<span class="op">()</span> <span class="op">-&gt;</span> T;</span>
<span id="cb6-2"><a href="#cb6-2"></a></span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="dt">void</span> construct_into<span class="op">(</span>T<span class="op">*</span> p<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-4"><a href="#cb6-4"></a>    <span class="co">// this definitely moves a T</span></span>
<span id="cb6-5"><a href="#cb6-5"></a>    std<span class="op">::</span>construct_at<span class="op">(</span>p, get_object<span class="op">())</span>;</span>
<span id="cb6-6"><a href="#cb6-6"></a></span>
<span id="cb6-7"><a href="#cb6-7"></a>    <span class="co">// this definitely does not move a T</span></span>
<span id="cb6-8"><a href="#cb6-8"></a>    <span class="op">:::</span><span class="kw">new</span> <span class="op">(</span>p<span class="op">)</span> T<span class="op">(</span>get_object<span class="op">())</span>;</span>
<span id="cb6-9"><a href="#cb6-9"></a></span>
<span id="cb6-10"><a href="#cb6-10"></a>    <span class="co">// this now also definitely does not move a T, but it isn&#39;t practical</span></span>
<span id="cb6-11"><a href="#cb6-11"></a>    <span class="co">// and you also have to deal with delightful edge cases - like what if</span></span>
<span id="cb6-12"><a href="#cb6-12"></a>    <span class="co">// T is actually constructible from defer?</span></span>
<span id="cb6-13"><a href="#cb6-13"></a>    <span class="kw">struct</span> defer <span class="op">{</span></span>
<span id="cb6-14"><a href="#cb6-14"></a>        <span class="kw">constexpr</span> <span class="kw">operator</span> T<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> get_object<span class="op">()</span>; <span class="op">}</span></span>
<span id="cb6-15"><a href="#cb6-15"></a>    <span class="op">}</span>;</span>
<span id="cb6-16"><a href="#cb6-16"></a>    std<span class="op">::</span>construct_at<span class="op">(</span>p, defer<span class="op">{})</span>;</span>
<span id="cb6-17"><a href="#cb6-17"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Placement new is only unsafe because the language allows you to do practically anything - want to placement new a <code class="sourceCode cpp">std<span class="op">::</span>string</code> into a <code class="sourceCode cpp"><span class="dt">double</span><span class="op">*</span></code>? Sure, why not. But during constant evaluation we already have a way of limiting operations to those that make sense - we can require that the pointer we’re constructing into actually is a <code class="sourceCode cpp">T<span class="op">*</span></code>. The fact that we have to go through a <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code> to get there doesn’t make it unsafe.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="uninitialized-objects"><span class="header-section-number">4</span> Uninitialized objects<a href="#uninitialized-objects" class="self-link"></a></h1>
<p>Since C++20, we can use <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code> during constant evaluation. But what about a type that doesn’t actually need allocation, like <code class="sourceCode cpp">static_vector<span class="op">&lt;</span>T, capacity<span class="op">&gt;</span></code>? That proposal (<span class="citation" data-cites="P0843R4">[<a href="#ref-P0843R4" role="doc-biblioref">P0843R4</a>]</span>) currently only supports <code class="sourceCode cpp"><span class="kw">constexpr</span></code> if <code class="sourceCode cpp">T</code> is trivially copyable and default constructible, because of issues with storage. David Stone covered this in a <a href="https://www.youtube.com/watch?v=I8QJLGI0GOE">recent CppCon talk</a>.</p>
<p>The issue there is you want to do something like… this:</p>
<blockquote>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> Capacity<span class="op">&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="kw">class</span> static_vector <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3"></a>    <span class="kw">alignas</span><span class="op">(</span>T<span class="op">)</span> std<span class="op">::</span>byte storage_<span class="op">[</span><span class="kw">sizeof</span><span class="op">(</span>T<span class="op">)</span> <span class="op">*</span> Capacity<span class="op">]</span>;</span>
<span id="cb7-4"><a href="#cb7-4"></a>    <span class="dt">size_t</span> size_;</span>
<span id="cb7-5"><a href="#cb7-5"></a></span>
<span id="cb7-6"><a href="#cb7-6"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb7-7"><a href="#cb7-7"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> data<span class="op">()</span> <span class="op">-&gt;</span> T<span class="op">*</span> <span class="op">{</span></span>
<span id="cb7-8"><a href="#cb7-8"></a>        <span class="cf">return</span> <span class="op">(</span>T<span class="op">*)</span>storage_;</span>
<span id="cb7-9"><a href="#cb7-9"></a>    <span class="op">}</span></span>
<span id="cb7-10"><a href="#cb7-10"></a></span>
<span id="cb7-11"><a href="#cb7-11"></a>    <span class="dt">void</span> push_back<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> rhs<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-12"><a href="#cb7-12"></a>        <span class="co">// check size vs capacity, etc, out of scope</span></span>
<span id="cb7-13"><a href="#cb7-13"></a>        <span class="op">::</span><span class="kw">new</span> <span class="op">(</span>data<span class="op">()</span> <span class="op">+</span> size_<span class="op">)</span> T<span class="op">(</span>rhs<span class="op">)</span>;</span>
<span id="cb7-14"><a href="#cb7-14"></a>        <span class="op">++</span>size_;</span>
<span id="cb7-15"><a href="#cb7-15"></a>    <span class="op">}</span></span>
<span id="cb7-16"><a href="#cb7-16"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>But here the problem is on top of the <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code> that we have to deal with from placement-new, we have the issue that the originating storage isn’t actually a <code class="sourceCode cpp">T</code> to begin with, it’s just an array of <code class="sourceCode cpp">std<span class="op">::</span>byte</code> (or <code class="sourceCode cpp"><span class="dt">char</span></code> or <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">char</span></code>). It can’t just be a <code class="sourceCode cpp">T<span class="op">[</span>Capacity<span class="op">]</span></code> because we want to avoid having to default-construct all of our <code class="sourceCode cpp">T</code>s.</p>
<p>We could try to change the storage to from the array of <code class="sourceCode cpp">std<span class="op">::</span>byte</code> to something like:</p>
<blockquote>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">union</span> U <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2"></a>  <span class="kw">constexpr</span> U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb8-3"><a href="#cb8-3"></a>  <span class="kw">constexpr</span> <span class="op">~</span>U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a>  T data<span class="op">[</span>N<span class="op">]</span>;</span>
<span id="cb8-6"><a href="#cb8-6"></a><span class="op">}</span> storage_;</span></code></pre></div>
</blockquote>
<p>This helps in the sense that our placement-new now does originate with a <code class="sourceCode cpp">T</code>, so we don’t have that particular concern. But we now have the added issue that at no point did we begin the lifetime of this union alternative. That is, consider this hilariously complex <a href="https://godbolt.org/z/xq9haKsvY">identity function</a>:</p>
<blockquote>
<div class="sourceCode" id="cb9"><pre class="sourceCode numberSource cpp numberLines"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a><span class="kw">constexpr</span> <span class="dt">int</span> id<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2"></a>    <span class="kw">struct</span> X <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3"></a>        <span class="dt">int</span> i;</span>
<span id="cb9-4"><a href="#cb9-4"></a>        <span class="kw">constexpr</span> X<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">:</span> i<span class="op">(</span>i<span class="op">)</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb9-5"><a href="#cb9-5"></a>    <span class="op">}</span>;</span>
<span id="cb9-6"><a href="#cb9-6"></a></span>
<span id="cb9-7"><a href="#cb9-7"></a>    <span class="kw">union</span> U <span class="op">{</span></span>
<span id="cb9-8"><a href="#cb9-8"></a>        <span class="kw">constexpr</span> U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb9-9"><a href="#cb9-9"></a>        <span class="kw">constexpr</span> <span class="op">~</span>U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb9-10"><a href="#cb9-10"></a>        X data<span class="op">[</span><span class="dv">1</span><span class="op">]</span>;</span>
<span id="cb9-11"><a href="#cb9-11"></a>    <span class="op">}</span>;</span>
<span id="cb9-12"><a href="#cb9-12"></a></span>
<span id="cb9-13"><a href="#cb9-13"></a>    U storage;</span>
<span id="cb9-14"><a href="#cb9-14"></a>    X<span class="op">*</span> x <span class="op">=</span> std<span class="op">::</span>construct_at<span class="op">(&amp;</span>storage<span class="op">.</span>data<span class="op">[</span><span class="dv">0</span><span class="op">]</span>, i<span class="op">)</span>;</span>
<span id="cb9-15"><a href="#cb9-15"></a>    <span class="cf">return</span> x<span class="op">-&gt;</span>i;</span>
<span id="cb9-16"><a href="#cb9-16"></a><span class="op">}</span></span>
<span id="cb9-17"><a href="#cb9-17"></a></span>
<span id="cb9-18"><a href="#cb9-18"></a><span class="kw">static_assert</span><span class="op">(</span>id<span class="op">(</span><span class="dv">42</span><span class="op">)</span> <span class="op">==</span> <span class="dv">42</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>On line 14 there, while <code class="sourceCode cpp"><span class="op">&amp;</span>storage<span class="op">.</span>data<span class="op">[</span><span class="dv">0</span><span class="op">]</span></code> is actually an <code class="sourceCode cpp">X<span class="op">*</span></code>, the <code class="sourceCode cpp">data</code> union alternative of <code class="sourceCode cpp">storage</code> isn’t active yet. Nothing constructed it. Nevertheless, as you can see in the compiler explorer link, gcc and msvc both accept this code.</p>
<p>How can we make this work? There’s a few directions, I think.</p>
<p>First, we can have the language recognize an uninitialized storage type. Like a <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>. Which, for the <code class="sourceCode cpp">static_vector</code> case, would be <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">[</span>Capacity<span class="op">]&gt;</span></code> This would be a type that’s just already much easier to use than the <code class="sourceCode cpp">std<span class="op">::</span>aligned_storage</code> that we deprecated (<span class="citation" data-cites="P1413R3">[<a href="#ref-P1413R3" role="doc-biblioref">P1413R3</a>]</span>) simply on the basis that you can’t misspell it. libstdc++, for instance, has an <code class="sourceCode cpp">__aligned_membuf<span class="op">&lt;</span>T<span class="op">&gt;</span></code> type with a pretty <a href="https://github.com/gcc-mirror/gcc/blob/3f101e32e2fb616633722fb552779f537e9a9891/libstdc%2B%2B-v3/include/ext/aligned_buffer.h#L46-L78">nice API</a> that could be the basis for this (except that the <code class="sourceCode cpp">ptr<span class="op">()</span></code> function should really return <code class="sourceCode cpp">remove_extent_t<span class="op">&lt;</span>T<span class="op">&gt;*</span></code> not just <code class="sourceCode cpp">T<span class="op">*</span></code>, to properly handle the array case). This seems like a good direction since it makes intent that much clearer and would be harder to misuse (since you can’t forget the alignment):</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>With buffer array</strong>
</div></th>
<th><div style="text-align:center">
<strong>With <code class="sourceCode cpp">std<span class="op">::</span>uninitialized</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> Capacity<span class="op">&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2"></a><span class="kw">class</span> static_vector <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3"></a>    <span class="kw">alignas</span><span class="op">(</span>T<span class="op">)</span> std<span class="op">::</span>byte storage_<span class="op">[</span><span class="kw">sizeof</span><span class="op">(</span>T<span class="op">)</span> <span class="op">*</span> Capacity<span class="op">]</span>;</span>
<span id="cb10-4"><a href="#cb10-4"></a>    <span class="dt">size_t</span> size_;</span>
<span id="cb10-5"><a href="#cb10-5"></a></span>
<span id="cb10-6"><a href="#cb10-6"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb10-7"><a href="#cb10-7"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> data<span class="op">()</span> <span class="op">-&gt;</span> T<span class="op">*</span> <span class="op">{</span></span>
<span id="cb10-8"><a href="#cb10-8"></a>        <span class="cf">return</span> <span class="op">(</span>T<span class="op">*)</span>storage_;</span>
<span id="cb10-9"><a href="#cb10-9"></a>    <span class="op">}</span></span>
<span id="cb10-10"><a href="#cb10-10"></a><span class="op">}</span>;</span></code></pre></div></td>
<td><div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> Capacity<span class="op">&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2"></a><span class="kw">class</span> static_vector <span class="op">{</span></span>
<span id="cb11-3"><a href="#cb11-3"></a>    std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T, N<span class="op">&gt;</span> storage_;</span>
<span id="cb11-4"><a href="#cb11-4"></a>    <span class="dt">size_t</span> size_;</span>
<span id="cb11-5"><a href="#cb11-5"></a></span>
<span id="cb11-6"><a href="#cb11-6"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb11-7"><a href="#cb11-7"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> data<span class="op">()</span> <span class="op">-&gt;</span> T<span class="op">*</span> <span class="op">{</span></span>
<span id="cb11-8"><a href="#cb11-8"></a>        <span class="cf">return</span> storage_<span class="op">.</span>data<span class="op">()</span>;</span>
<span id="cb11-9"><a href="#cb11-9"></a>    <span class="op">}</span></span>
<span id="cb11-10"><a href="#cb11-10"></a><span class="op">}</span>;</span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>Second, we could simply bless the union example from earlier. That is, it’s already the case that a placement new (or, for now, <code class="sourceCode cpp">std<span class="op">::</span>construct_at</code>) on a union alternative changes that to be the active alternative. But we could extend that to be true for if you are constructing a subobject of an alternative (or, at the very least, an array member). This approach isn’t actually mutually exclusive with <code class="sourceCode cpp">std<span class="op">::</span>uninitialized</code> - it just makes <code class="sourceCode cpp">std<span class="op">::</span>uninitialized</code> something that can be implemented outside of the standard library. Depending on your perspective, that’s either very good (less magic things in the language that can only be implemented by the compiler) or very bad (allows for multiple different implementations of <code class="sourceCode cpp">std<span class="op">::</span>uninitialized</code>).</p>
<p>An alternative to making the union example work is to provide a mechanism to start the lifetime of a union alternative but performing no initialization. One idea discussed in context of JF Bastien’s <span class="citation" data-cites="P2723R0">[<a href="#ref-P2723R0" role="doc-biblioref">P2723R0</a>]</span> was the ability to explicitly denote no initialization, not as an attribute but using some kind of syntax. Some ideas that I’ve seen thrown around were:</p>
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1"></a><span class="dt">void</span> test<span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2"></a>  <span class="dt">int</span> a;                  <span class="co">// zero-initialized, per the paper</span></span>
<span id="cb12-3"><a href="#cb12-3"></a>  <span class="dt">int</span> b <span class="op">=</span> <span class="dt">void</span>;           <span class="co">// uninitialized (explicitly)</span></span>
<span id="cb12-4"><a href="#cb12-4"></a>  <span class="dt">int</span> c <span class="op">=</span> uninitialized;  <span class="co">// uninitialized (explicitly)</span></span>
<span id="cb12-5"><a href="#cb12-5"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>The advantage of the syntax over the attribute in this particular case is that the storage example could be implemented as:</p>
<blockquote>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2"></a><span class="kw">union</span> storage_for <span class="op">{</span></span>
<span id="cb13-3"><a href="#cb13-3"></a>    <span class="kw">constexpr</span> <span class="op">~</span>storage_for<span class="op">()</span> <span class="kw">requires</span> std<span class="op">::</span>is_trivially_destructible_v<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb13-4"><a href="#cb13-4"></a>    <span class="kw">constexpr</span> <span class="op">~</span>storage_for<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb13-5"><a href="#cb13-5"></a></span>
<span id="cb13-6"><a href="#cb13-6"></a>    T data <span class="op">=</span> <span class="dt">void</span>; <span class="co">// or whatever syntax</span></span>
<span id="cb13-7"><a href="#cb13-7"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>We’d still need it to be a union, because we need to avoid destruction, but at least this gives us an active union member that we could then safely use.</p>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="proposal"><span class="header-section-number">5</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>This paper proposes extending constant evaluation support to cover a lot more interesting cases by striking the rule about conversion from <code class="sourceCode cpp"><em>cv</em> <span class="dt">void</span><span class="op">*</span></code>. We still require that reading through a <code class="sourceCode cpp">T<span class="op">*</span></code> is only valid if actually points to a <code class="sourceCode cpp">T</code> (as in, the <code class="sourceCode cpp"><span class="dt">void</span><span class="op">*</span></code> had to have been obtained by a <code class="sourceCode cpp"><span class="kw">static_cast</span></code> from a <code class="sourceCode cpp">T<span class="op">*</span></code>) - this doesn’t open the door for various type punning shenanigans during constant evaluation time. These are all conversions that would only be allowed if they were actually valid.</p>
<p>Allowing converting from <code class="sourceCode cpp"><em>cv</em> <span class="dt">void</span><span class="op">*</span></code> to <code class="sourceCode cpp"><em>cv</em> T<span class="op">*</span></code>, if there is actually a <code class="sourceCode cpp">T</code> there, should immediately allow placement-new to work, but this may require explicit permission for global placement new in the same place where we currently have explicit permission for <code class="sourceCode cpp">std<span class="op">::</span>construct_at</code>.</p>
<p>Lastly, this paper proposes that placement new on an array alternative of a union implicitly starts the lifetime of the whole array alternative. This seems consistent with the implicit-lifetime-type rule that we have for arrays, and is the minimal change required to allow <code class="sourceCode cpp">static_vector</code> to work and to allow user implementations of <code class="sourceCode cpp">uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>. I’m not proposing <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code> specifically because I don’t think it’s strictly necessary, and the shape of it will largely end up depending on the discussion around JF’s paper - which is otherwise completely unrelated to this paper.</p>
<p>Importantly, the changes proposed here allow code that people would already be writing today to simply work during compile time as well. Well, for uninitialized storage people probably use an aligned array of bytes rather than a union with an array of <code class="sourceCode cpp">T</code>, but least this isn’t too far off, and the main point is that the proposal isn’t inventing a new way of writing compile-time-friendly code.</p>
<h2 data-number="5.1" id="implementation-concerns"><span class="header-section-number">5.1</span> Implementation Concerns<a href="#implementation-concerns" class="self-link"></a></h2>
<p>One of the raised concerns against allowing conversion from <code class="sourceCode cpp"><em>cv</em> <span class="dt">void</span><span class="op">*</span></code> in the way proposed by this paper is the cost to certain implementations of tracking pointers - specifically in the cost of validating this conversion. However, while everyone would obviously prefer things to be as fast to compile as possible, we’re not choosing here between a fast approach and a slow approach - the decision here is between a slow approach and <em>no approach at all</em>. The inability to convert from <code class="sourceCode cpp"><em>cv</em> <span class="dt">void</span><span class="op">*</span></code> means we can’t have a certain class of type erasure, we can’t do several kinds of placement new and other kinds efficiently, and we can’t have a <code class="sourceCode cpp"><span class="kw">constexpr</span> static_vector</code> without introducing more special cases for magic library names. I don’t think that’s a good trade-off.</p>
<h1 data-number="6" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">6</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-P0784R7">
<p>[P0784R7] Daveed Vandevoorde, Peter Dimov,Louis Dionne, Nina Ranns, Richard Smith, Daveed Vandevoorde. 2019-07-22. More constexpr containers. <br />
<a href="https://wg21.link/p0784r7">https://wg21.link/p0784r7</a></p>
</div>
<div id="ref-P0843R4">
<p>[P0843R4] Gonzalo Brito Gadeschi. 2020-01-13. static_vector. <br />
<a href="https://wg21.link/p0843r4">https://wg21.link/p0843r4</a></p>
</div>
<div id="ref-P1413R3">
<p>[P1413R3] CJ Johnson. 2021-11-22. Deprecate std::aligned_storage and std::aligned_union. <br />
<a href="https://wg21.link/p1413r3">https://wg21.link/p1413r3</a></p>
</div>
<div id="ref-P2283R1">
<p>[P2283R1] Michael Schellenberger Costa. 2021-04-19. constexpr for specialized memory algorithms. <br />
<a href="https://wg21.link/p2283r1">https://wg21.link/p2283r1</a></p>
</div>
<div id="ref-P2283R2">
<p>[P2283R2] Michael Schellenberger Costa. 2021-11-26. constexpr for specialized memory algorithms. <br />
<a href="https://wg21.link/p2283r2">https://wg21.link/p2283r2</a></p>
</div>
<div id="ref-P2723R0">
<p>[P2723R0] JF Bastien. 2022-11-16. Zero-initialize objects of automatic storage duration. <br />
<a href="https://wg21.link/p2723r0">https://wg21.link/p2723r0</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
