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

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
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: #C9FBC9;
--diff-strongins: #acf2bd;
--diff-del: #FFC8EB;
--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); }
div.std blockquote { color: #000000; background-color: #F1F1F1;
border: 1px solid #D1D1D1;
padding-left: 0.5em; padding-right: 0.5em; }
div.std.ins blockquote {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.ins > div.example {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.std div.sourceCode { background-color: inherit; margin-left: 1em; }
div.std blockquote del { text-decoration: line-through;
color: #000000; background-color: var(--diff-del);
border: none; }
code del { border: 1px solid #ECB3C7; }
span.orange {
background-color: #ffa500;
}
span.yellow {
background-color: #ffff00;
}</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">trivial
<code class="sourceCode cpp"><span class="kw">union</span></code>s (was
<code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>)</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3074R5 <a href="https://wg21.link/P3074">[Latest]</a> <a href="https://wg21.link/P3074/status">[Status]</a></td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-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="/cdn-cgi/l/email-protection#4b292a39393265392e3d3122250b2c262a222765282426" class="email"><span class="__cf_email__" data-cfemail="2b494a59595205594e5d5142456b4c464a424705484446">[email&#160;protected]</span></a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">1</span> Revision
History<span></span></a></li>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">2</span> Introduction<span></span></a>
<ul>
<li><a href="#the-uninitialized-storage-problem" id="toc-the-uninitialized-storage-problem"><span class="toc-section-number">2.1</span> The uninitialized storage
problem<span></span></a></li>
</ul></li>
<li><a href="#design-space" id="toc-design-space"><span class="toc-section-number">3</span> Design Space<span></span></a>
<ul>
<li><a href="#a-library-type-stduninitializedt" id="toc-a-library-type-stduninitializedt"><span class="toc-section-number">3.1</span> A library type: <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code><span></span></a></li>
<li><a href="#a-language-annotation" id="toc-a-language-annotation"><span class="toc-section-number">3.2</span> A language
annotation<span></span></a></li>
<li><a href="#just-make-it-work" id="toc-just-make-it-work"><span class="toc-section-number">3.3</span> Just make it
work<span></span></a></li>
<li><a href="#trivial-unions" id="toc-trivial-unions"><span class="toc-section-number">3.4</span> Trivial
Unions<span></span></a></li>
<li><a href="#existing-practice" id="toc-existing-practice"><span class="toc-section-number">3.5</span> Existing
Practice<span></span></a></li>
<li><a href="#st.-louis-meeting-2024" id="toc-st.-louis-meeting-2024"><span class="toc-section-number">3.6</span> St. Louis Meeting,
2024<span></span></a></li>
<li><a href="#just-to-double-check" id="toc-just-to-double-check"><span class="toc-section-number">3.7</span> Just to Double
Check<span></span></a></li>
<li><a href="#constructordestructor-intention-matching" id="toc-constructordestructor-intention-matching"><span class="toc-section-number">3.8</span> Constructor/Destructor Intention
Matching<span></span></a></li>
</ul></li>
<li><a href="#proposal" id="toc-proposal"><span class="toc-section-number">4</span> Proposal<span></span></a>
<ul>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">4.1</span> Implementation
Experience<span></span></a></li>
<li><a href="#language-wording" id="toc-language-wording"><span class="toc-section-number">4.2</span> Language
Wording<span></span></a></li>
<li><a href="#library-wording" id="toc-library-wording"><span class="toc-section-number">4.3</span> Library
Wording<span></span></a></li>
<li><a href="#feature-test-macro" id="toc-feature-test-macro"><span class="toc-section-number">4.4</span> Feature-Test
Macro<span></span></a></li>
</ul></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">5</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="revision-history"><span class="header-section-number">1</span>
Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>Since <span class="citation" data-cites="P3074R4">[<a href="https://wg21.link/p3074r4" role="doc-biblioref">P3074R4</a>]</span>, wording changes and adjusted
the rule for when a <a href="#constructordestructor-intention-matching">union’s destructor is
deleted</a></p>
<p>Since <span class="citation" data-cites="P3074R3">[<a href="https://wg21.link/p3074r3" role="doc-biblioref">P3074R3</a>]</span>, in <a href="https://github.com/cplusplus/papers/issues/1734#issuecomment-2195769496">St. Louis</a>,
EWG had expressed a clear preference for “just make it work”:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>4</td>
<td>14</td>
<td>3</td>
<td>2</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>over <code class="sourceCode cpp">trivial <span class="kw">union</span></code>:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>0</td>
<td>3</td>
<td>13</td>
<td>4</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>So proposing to make it work and adding <a href="#implementation-experience">implementation experience</a>.</p>
<p>Since <span class="citation" data-cites="P3074R2">[<a href="https://wg21.link/p3074r2" role="doc-biblioref">P3074R2</a>]</span>, changed to instead propose a
language change to unions (with two options) to solve the problems
presented</p>
<p>Since <span class="citation" data-cites="P3074R1">[<a href="https://wg21.link/p3074r1" role="doc-biblioref">P3074R1</a>]</span>, the <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
design was designed in an EWG telecon and the suggestion was made to
make this a language feature. Added a section to argue against and
re-spelled <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
to be a union instead of a class containing an anonymous union.</p>
<p>Since <span class="citation" data-cites="P3074R0">[<a href="https://wg21.link/p3074r0" role="doc-biblioref">P3074R0</a>]</span>, originally proposed the
function <code class="sourceCode cpp">std<span class="op">::</span>start_lifetime<span class="op">(</span>p<span class="op">)</span></code>.
R1 adds a new section discussing the <a href="#the-uninitialized-storage-problem">uninitialized storage
problem</a>, which motivates a change in design to instead propose <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">2</span>
Introduction<a href="#introduction" class="self-link"></a></h1>
<p>Consider the following example:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> FixedVector <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">union</span> U <span class="op">{</span> <span class="kw">constexpr</span> U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span> <span class="kw">constexpr</span> <span class="op">~</span>U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span> T storage<span class="op">[</span>N<span class="op">]</span>; <span class="op">}</span>;</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    U u;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> size <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="co">// note: we are *not* constructing storage</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> FixedVector<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="op">~</span>FixedVector<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>destroy<span class="op">(</span>u<span class="op">.</span>storage, u<span class="op">.</span>storage<span class="op">+</span>size<span class="op">)</span>;</span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> push_back<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> v<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>construct_at<span class="op">(</span>u<span class="op">.</span>storage <span class="op">+</span> size, v<span class="op">)</span>;</span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span>size;</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> silly_test<span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">size_t</span> <span class="op">{</span></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>    FixedVector<span class="op">&lt;</span>std<span class="op">::</span>string, <span class="dv">3</span><span class="op">&gt;</span> v;</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>    v<span class="op">.</span>push_back<span class="op">(</span><span class="st">&quot;some sufficiently longer string&quot;</span><span class="op">)</span>;</span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> v<span class="op">.</span>size;</span>
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>silly_test<span class="op">()</span> <span class="op">==</span> <span class="dv">1</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
</div>
<p>This is basically how any static/non-allocating/in-place vector is
implemented: we have some storage, that we <em>definitely do not value
initialize</em> and then we steadily construct elements into it.</p>
<p>The problem is that the above does not work (although there is <a href="https://godbolt.org/z/a3318n63v">implementation divergence</a> -
MSVC and EDG accept it and GCC did accept it even up to 13.2, but GCC
trunk and Clang reject).</p>
<p>Getting this example to work would allow <code class="sourceCode cpp">std<span class="op">::</span>inplace_vector</code>
(<span class="citation" data-cites="P0843R14">[<a href="https://wg21.link/p0843r14" role="doc-biblioref">P0843R14</a>]</span>) to simply work during
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
time for all times (instead of just trivial ones), and was a problem
briefly touched on in <span class="citation" data-cites="P2747R0">[<a href="https://wg21.link/p2747r0" role="doc-biblioref">P2747R0</a>]</span>.</p>
<h2 data-number="2.1" id="the-uninitialized-storage-problem"><span class="header-section-number">2.1</span> The uninitialized storage
problem<a href="#the-uninitialized-storage-problem" class="self-link"></a></h2>
<p>A closely related problem to the above is: how do you do
uninitialized storage? The straightforward implementation would be to
do:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> BufferStorage <span class="op">{</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">alignas</span><span class="op">(</span>T<span class="op">)</span> <span class="dt">unsigned</span> <span class="dt">char</span> buffer<span class="op">[</span><span class="kw">sizeof</span><span class="op">(</span>T<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><span class="kw">public</span><span class="op">:</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="co">// accessors</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>This approach generally works, but it has two limitations:</p>
<ol type="1">
<li>it cannot work in
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
and that’s likely a fundamental limitation that will never change,
and</li>
<li>it does not quite handle overlapping objects correctly.</li>
</ol>
<p>What I mean by the second one is basically given this structure:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Empty <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Sub <span class="op">:</span> Empty <span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    BufferStorage<span class="op">&lt;</span>Empty<span class="op">&gt;</span> buffer_storage;</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>If we initialize the <code class="sourceCode cpp">Empty</code> that
<code class="sourceCode cpp">buffer_storage</code> is intended to have,
then <code class="sourceCode cpp">Sub</code> has two subobjects of type
<code class="sourceCode cpp">Empty</code>. But the compiler doesn’t
really… know that, and doesn’t adjust them accordingly. As a result, the
<code class="sourceCode cpp">Empty</code> base class subobject and the
<code class="sourceCode cpp">Empty</code> initialized in
<code class="sourceCode cpp">buffer_storage</code> are at the same
address, which violates the rule that all objects of one type are at
unique addresses.</p>
<p>An alternative approach to storage is to use a
<code class="sourceCode cpp"><span class="kw">union</span></code>:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> UnionStorage <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">union</span> <span class="op">{</span> T value; <span class="op">}</span>;</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="co">// accessors</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> Sub <span class="op">:</span> Empty <span class="op">{</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>    UnionStorage<span class="op">&lt;</span>Empty<span class="op">&gt;</span> union_storage;</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>Here, now the compiler knows for sure there is an
<code class="sourceCode cpp">Empty</code> in
<code class="sourceCode cpp">union_storage</code> and will lay out the
types appropriately. See also <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112591">gcc bug
112591</a>.</p>
<p>So it seems that the <code class="sourceCode cpp">UnionStorage</code>
approach is strictly superior: it will work in constexpr and it lays out
overlapping types properly. But it has limitations of its own. As with
the <code class="sourceCode cpp">FixedVector</code> example earlier, you
cannot just start the lifetime of
<code class="sourceCode cpp">value</code>. But also in this case we run
into the
<code class="sourceCode cpp"><span class="kw">union</span></code> rules
for special member functions: a special member of a
<code class="sourceCode cpp"><span class="kw">union</span></code>, by
default, is either trivial (if that special member for all alternatives
is trivial) or deleted (otherwise). Which means that <code class="sourceCode cpp">UnionStorage<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span></code>
has both its constructor and destructor <em>deleted</em>.</p>
<p>We can work around this by simply adding an empty constructor and
destructor (as shown earlier as well):</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> UnionStorage2 <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">union</span> U <span class="op">{</span> U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span> <span class="op">~</span>U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span> T value; <span class="op">}</span>;</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  U u;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">// accessors</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>This is a fundamentally weird concept since
<code class="sourceCode cpp">U</code> there has a destructor that does
nothing (and given that this is a class to be used for uninitialized
storage), it <em>should</em> do nothing - that’s correct. But that
destructor still isn’t trivial. And it turns out there is still a
difference between “destructor that does nothing” and “trivial
destructor”:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Trivially Destructible</strong>
</div></th>
<th><div style="text-align:center">
<strong>Non-trivially Destructible</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<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">struct</span> A <span class="op">{</span> <span class="op">}</span>;</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> alloc_a<span class="op">(</span><span class="dt">int</span> n<span class="op">)</span> <span class="op">-&gt;</span> A<span class="op">*</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">new</span> A<span class="op">[</span>n<span class="op">]</span>; <span class="op">}</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> del<span class="op">(</span>A<span class="op">*</span> p<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span> <span class="kw">delete</span> <span class="op">[]</span> p; <span class="op">}</span></span></code></pre></div>

</div></td>
<td><div>

<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">struct</span> B <span class="op">{</span> <span class="op">~</span>B<span class="op">()</span> <span class="op">{</span> <span class="op">}</span> <span class="op">}</span>;</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> alloc_b<span class="op">(</span><span class="dt">int</span> n<span class="op">)</span> <span class="op">-&gt;</span> B<span class="op">*</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">new</span> B<span class="op">[</span>n<span class="op">]</span>; <span class="op">}</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> del<span class="op">(</span>B<span class="op">*</span> p<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span> <span class="kw">delete</span> <span class="op">[]</span> p; <span class="op">}</span></span></code></pre></div>

</div></td>
</tr>
<tr class="even">
<td><div>

<div class="sourceCode" id="cb1"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>alloc_a<span class="op">(</span>int<span class="op">):</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movsx</span>   <span class="kw">rdi</span><span class="op">,</span> <span class="kw">edi</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>        <span class="cf">jmp</span>     operator new<span class="op">[](</span>unsigned long<span class="op">)</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>del<span class="op">(</span>A<span class="op">*):</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        <span class="bu">test</span>    <span class="kw">rdi</span><span class="op">,</span> <span class="kw">rdi</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>        <span class="cf">je</span>      <span class="op">.</span>L3</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>        <span class="cf">jmp</span>     operator delete<span class="op">[](</span>void<span class="op">*)</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="fu">.L3:</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>        <span class="cf">ret</span></span></code></pre></div>

</div></td>
<td><div>

<div class="sourceCode" id="cb2"><pre class="sourceCode asm"><code class="sourceCode fasm"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>alloc_b<span class="op">(</span>int<span class="op">):</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>        movabs  <span class="kw">rax</span><span class="op">,</span> <span class="dv">9223372036854775800</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>        <span class="bu">push</span>    <span class="kw">rbx</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>        <span class="bu">movsx</span>   <span class="kw">rbx</span><span class="op">,</span> <span class="kw">edi</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>        <span class="bu">cmp</span>     <span class="kw">rax</span><span class="op">,</span> <span class="kw">rbx</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>        <span class="bu">lea</span>     <span class="kw">rdi</span><span class="op">,</span> <span class="op">[</span><span class="kw">rbx</span><span class="op">+</span><span class="dv">8</span><span class="op">]</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>        <span class="bu">mov</span>     <span class="kw">rax</span><span class="op">,</span> <span class="op">-</span><span class="dv">1</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>        <span class="bu">cmovb</span>   <span class="kw">rdi</span><span class="op">,</span> <span class="kw">rax</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">call</span>    operator new<span class="op">[](</span>unsigned long<span class="op">)</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>        <span class="bu">mov</span>     <span class="dt">QWORD</span> <span class="dt">PTR</span> <span class="op">[</span><span class="kw">rax</span><span class="op">],</span> <span class="kw">rbx</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>        <span class="bu">add</span>     <span class="kw">rax</span><span class="op">,</span> <span class="dv">8</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>        <span class="bu">pop</span>     <span class="kw">rbx</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>        <span class="cf">ret</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>del<span class="op">(</span>B<span class="op">*):</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>        <span class="bu">test</span>    <span class="kw">rdi</span><span class="op">,</span> <span class="kw">rdi</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>        <span class="cf">je</span>      <span class="op">.</span>L9</span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>        <span class="bu">mov</span>     <span class="kw">rax</span><span class="op">,</span> <span class="dt">QWORD</span> <span class="dt">PTR</span> <span class="op">[</span><span class="kw">rdi</span><span class="op">-</span><span class="dv">8</span><span class="op">]</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>        <span class="bu">sub</span>     <span class="kw">rdi</span><span class="op">,</span> <span class="dv">8</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>        <span class="bu">lea</span>     <span class="kw">rsi</span><span class="op">,</span> <span class="op">[</span><span class="kw">rax</span><span class="op">+</span><span class="dv">8</span><span class="op">]</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>        <span class="cf">jmp</span>     operator delete<span class="op">[](</span>void<span class="op">*,</span> unsigned long<span class="op">)</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a><span class="fu">.L9:</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>        <span class="cf">ret</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>That’s a big difference in code-gen, due to the need to put a cookie
in the allocation so that the corresponding <code class="sourceCode cpp"><span class="kw">delete</span><span class="op">[]</span></code>
knows how many elements there so that their destructors (even though
they do nothing!) can be invoked.</p>
<p>While the union storage solution solves some language problems for
us, the buffer storage solution can lead to more efficient code -
because <code class="sourceCode cpp">StorageBuffer<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
is always trivially destructible. It would be nice if he had a good
solution to all of these problems - and that solution was also the most
efficient one.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="design-space"><span class="header-section-number">3</span> Design
Space<a href="#design-space" class="self-link"></a></h1>
<p>There are several potential solutions in this space:</p>
<ol type="1">
<li>a library solution (add a <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>)</li>
<li>a language solution (add some annotation to members to mark them
uninitialized, as distinct from
<code class="sourceCode cpp"><span class="kw">union</span></code>s)</li>
<li>just make it work (change the union rules to implicitly start the
lifetime of the first alternative, if it’s an implicit-lifetime
type)</li>
<li>introduce a new kind of union</li>
<li>provide an explicit function to start lifetime of a union
alternative (<code class="sourceCode cpp">std<span class="op">::</span>start_lifetime</code>).</li>
</ol>
<p>The first revision of this paper (<span class="citation" data-cites="P3074R0">[<a href="https://wg21.link/p3074r0" role="doc-biblioref">P3074R0</a>]</span>) proposed that last option.
However, with the addition of the overlapping subobjects problem and the
realization that the union solution has overhead compared to the buffer
storage solution, it would be more desirable to solve both problems in
one go. That is, it’s not enough to just start the lifetime of the
alternative, we also want a trivially constructible/destructible
solution for uninitialized storage.</p>
<p><span class="citation" data-cites="P3074R1">[<a href="https://wg21.link/p3074r1" role="doc-biblioref">P3074R1</a>]</span> and <span class="citation" data-cites="P3074R2">[<a href="https://wg21.link/p3074r2" role="doc-biblioref">P3074R2</a>]</span> proposed the first solution
(<code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>).
<span class="citation" data-cites="P3074R3">[<a href="https://wg21.link/p3074r3" role="doc-biblioref">P3074R3</a>]</span> proposed either the third or
fourth. This revision (R4) proposes specifically the third (just make it
work).</p>
<p>Let’s go over some of the solutions.</p>
<h2 data-number="3.1" id="a-library-type-stduninitializedt"><span class="header-section-number">3.1</span> A library type: <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code><a href="#a-library-type-stduninitializedt" class="self-link"></a></h2>
<p>We could introduce another magic library type, <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
with an interface like:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> uninitialized <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">union</span> <span class="op">{</span> T value; <span class="op">}</span>;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>As basically a better version of <code class="sourceCode cpp">std<span class="op">::</span>aligned_storage</code>.
Here is storage for a <code class="sourceCode cpp">T</code>, that
implicitly begins its lifetime if <code class="sourceCode cpp">T</code>
is an implicit-lifetime-type, but otherwise will not actually initialize
it for you - you have to do that yourself. Likewise it will not destroy
it for you, you have to do that yourself too. This type would be
specified to always be trivially default constructible and trivially
destructible. It would be trivially copyable if
<code class="sourceCode cpp">T</code> is trivially copyable, otherwise
not copyable.</p>
<p><code class="sourceCode cpp">std<span class="op">::</span>inplace_vector<span class="op">&lt;</span>T, N<span class="op">&gt;</span></code>
would then have a <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">[</span>N<span class="op">]&gt;</span></code>
and go ahead and <code class="sourceCode cpp">std<span class="op">::</span>construct_at</code>
(or, with <span class="citation" data-cites="P2747R2">[<a href="https://wg21.link/p2747r2" role="doc-biblioref">P2747R2</a>]</span>, simply placement-new) into the
appropriate elements of that array and everything would just work.</p>
<p>Because the language would recognize this type, this would also solve
the overlapping objects problem.</p>
<h2 data-number="3.2" id="a-language-annotation"><span class="header-section-number">3.2</span> A language annotation<a href="#a-language-annotation" class="self-link"></a></h2>
<p>During the EWG telecon in <a href="https://wiki.edg.com/bin/view/Wg21telecons2024/P3074R1-EWG">January
2023</a>, the suggestion was made that instead of a magic library type
like <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
we could instead have some kind of language annotation to achieve the
same effect.</p>
<p>For example:</p>
<div class="std">
<blockquote>
<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">typename</span> T, <span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> FixedVector <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="co">// as a library feature</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">[</span>N<span class="op">]&gt;</span> lib;</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">//as a language feature, something like this</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> storage T lang<span class="op">[</span>N<span class="op">]</span>;</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    T storage<span class="op">[</span>N<span class="op">]</span> <span class="op">=</span> <span class="cf">for</span> lang;</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a>    T storage<span class="op">[</span>N<span class="op">]</span> <span class="op">=</span> <span class="dt">void</span>;</span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>    uninitialized T lang<span class="op">[</span>N<span class="op">]</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="dt">size_t</span> size <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>The advantage of the language syntax is that you can directly use
<code class="sourceCode cpp">lang</code> - you would placement new onto
<code class="sourceCode cpp">lang<span class="op">[</span><span class="dv">0</span><span class="op">]</span></code>,
you read from <code class="sourceCode cpp">lang<span class="op">[</span><span class="dv">1</span><span class="op">]</span></code>,
etc, whereas with the library syntax you have to placement new onto
<code class="sourceCode cpp">lib<span class="op">.</span>value<span class="op">[</span><span class="dv">0</span><span class="op">]</span></code>
and read from <code class="sourceCode cpp">lib<span class="op">.</span>value<span class="op">[</span><span class="dv">1</span><span class="op">]</span></code>,
etc.</p>
<p>In that telecon, there was preference (including by me) for the
language solution:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>5</td>
<td>4</td>
<td>4</td>
<td>2</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>However, an uninitialized object of type
<code class="sourceCode cpp">T</code> really isn’t the same thing as a
<code class="sourceCode cpp">T</code>. <code class="sourceCode cpp"><span class="kw">decltype</span><span class="op">(</span>lang<span class="op">)</span></code>
would have to be <code class="sourceCode cpp">T</code>, any kind of
(imminent) reflection over this type would give you a
<code class="sourceCode cpp">T</code>. But there might not actually be a
<code class="sourceCode cpp">T</code> there yet, it behaves like a <code class="sourceCode cpp"><span class="kw">union</span> <span class="op">{</span> T; <span class="op">}</span></code>
rather than a <code class="sourceCode cpp">T</code>, so spelling it
<code class="sourceCode cpp">T</code> strikes me as misleading.</p>
<p>We would have to ensure that all the other member-wise algorithms we
have today (the special member functions and the comparisons) use the
“uninitialized <code class="sourceCode cpp">T</code>” meaning rather
than the <code class="sourceCode cpp">T</code> meaning. And with
reflection, that also means all future member-wise algorithms would have
to account for this also - rather than rejecting
<code class="sourceCode cpp"><span class="kw">union</span></code>s. This
seems to open the door to a lot of mistakes.</p>
<p>The syntactic benefits of the language syntax are nice, but this is a
rarely used type for specific situations - so having slightly longer
syntax (and really,
<code class="sourceCode cpp">lib<span class="op">.</span>value</code> is
not especially cumbersome) is not only not a big downside here but could
even be viewed as a benefit.</p>
<p>For this reason, R2 of this paper still proposed <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
as the solution in preference to any language annotation. This did not
go over well in <a href="https://github.com/cplusplus/papers/issues/1734#issuecomment-2012474793">Tokyo</a>,
where again there was preference for the language solution:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>6</td>
<td>7</td>
<td>3</td>
<td>4</td>
<td>2</td>
</tr>
</tbody>
</table>
<p>This leads to…</p>
<h2 data-number="3.3" id="just-make-it-work"><span class="header-section-number">3.3</span> Just make it work<a href="#just-make-it-work" class="self-link"></a></h2>
<p>Now, for the <code class="sourceCode cpp">inplace_vector</code>
problem, today’s
<code class="sourceCode cpp"><span class="kw">union</span></code> is
insufficient:</p>
<div class="std">
<blockquote>
<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><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> FixedVector <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">union</span> <span class="op">{</span> T storage<span class="op">[</span>N<span class="op">]</span>; <span class="op">}</span>;</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> size <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>Similarly a simple <code class="sourceCode cpp"><span class="kw">union</span> <span class="op">{</span> T storage; <span class="op">}</span></code>
is insufficient for the uninitialized storage problem.</p>
<p>There are three reasons for this:</p>
<ol type="1">
<li>the default constructor can be deleted (this can be easily worked
around though)</li>
<li>the default constructor does not start the lifetime of implicit
lifetime types</li>
<li>the destructor can be deleted (this can be worked around by
providing a no-op destructor, which has ABI cost that cannot be worked
around)</li>
</ol>
<p>However, what if instead of coming up with a solution for these
problems, we just… made it work?</p>
<p>That is, change the union rules as follows:</p>
<table>
<colgroup>
<col style="width: 33%" />
<col style="width: 33%" />
<col style="width: 33%" />
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>member</strong>
</div></th>
<th><div style="text-align:center">
<strong>status quo</strong>
</div></th>
<th><div style="text-align:center">
<strong>new rule</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>default constructor<br />(absent default member initializers)</td>
<td>If all the alternatives are trivially default constructible,
trivial.<br />Otherwise, deleted.</td>
<td>Unconditionally trivial<br />If the first alternative has
implicit-lifetime type, starts the lifetime of that alternative and sets
it as the active member (no initialization is performed).</td>
</tr>
<tr class="even">
<td>destructor</td>
<td>If all the alternatives are trivially destructible,
trivial.<br />Otherwise, deleted.</td>
<td>Unconditionally trivial.</td>
</tr>
</tbody>
</table>
<p>This isn’t quite a <em>minimal</em> extension, we could make it even
more minimal by only allowing a trivial default constructor and trivial
destructor for implicit-lifetime types, as in:</p>
<div class="std">
<blockquote>
<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="co">// default constructor and destructor are both deleted</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U1 <span class="op">{</span> std<span class="op">::</span>string s; <span class="op">}</span>;</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="co">// default constructor and destructor are both trivial</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U2 <span class="op">{</span> std<span class="op">::</span>string a<span class="op">[</span><span class="dv">1</span><span class="op">]</span>; <span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>But that doesn’t seem like a useful distinction to make. It’s also
actively harmful — for uninitialized storage, we really want trivial
construction/destruction. And it would be nice to not have to resort to
having members of type <code class="sourceCode cpp">T<span class="op">[</span><span class="dv">1</span><span class="op">]</span></code>
instead of <code class="sourceCode cpp">T</code> to achieve this.</p>
<p>Simply stating that the default constructor (absent default member
initializers) and destructor are always trivial is a simple rule.</p>
<h2 data-number="3.4" id="trivial-unions"><span class="header-section-number">3.4</span> Trivial Unions<a href="#trivial-unions" class="self-link"></a></h2>
<p>What if we introduced a new kind of union, with special annotation?
That is:</p>
<div class="std">
<blockquote>
<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">typename</span> T, <span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> FixedVector <span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    trivial <span class="kw">union</span> <span class="op">{</span> T storage<span class="op">[</span>N<span class="op">]</span>; <span class="op">}</span>;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="dt">size_t</span> size <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>With the rule that a trivial union is just always trivially default
constructible, trivially destructible, and, if the first alternative is
implicit-lifetime, starts the lifetime of that alternative (and sets it
to be the active member).</p>
<p>This is a language solution that doesn’t have any of the consequences
for memberwise algorithms - since we’re still a
<code class="sourceCode cpp"><span class="kw">union</span></code>. It
provides a clean solution to the uninitialized storage problem, the
aliasing problem, and the constexpr
<code class="sourceCode cpp">inplace_vector</code> storage problem.
Without having to deal with potentially changing behavior of existing
unions.</p>
<p>This brings up the question about default member initializers. Should
a <code class="sourceCode cpp">trivial <span class="kw">union</span></code> be
allowed to have a default member initializer? I don’t think so. If
you’re initializing the thing, it’s not really uninitialized storage
anymore. Use a regular union.</p>
<p>An alternative spelling for this might be <code class="sourceCode cpp">uninitialized <span class="kw">union</span></code>
instead of <code class="sourceCode cpp">trivial <span class="kw">union</span></code>. An
alternative alternative would be to instead provide a different way of
declaring the constructor and destructor:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U <span class="op">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>  U<span class="op">()</span> <span class="op">=</span> trivial;</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  <span class="op">~</span>U<span class="op">()</span> <span class="op">=</span> trivial;</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>  T storage<span class="op">[</span>N<span class="op">]</span>;</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>This is explicit (unlike <a href="#just-make-it-work">just making it
work</a>), but seems unnecessary much to type compared to a single
<code class="sourceCode cpp">trivial</code> token - and these things
really aren’t orthogonal. Plus it wouldn’t allow for anonymous trivial
unions, which seems like a nice usability gain.</p>
<h2 data-number="3.5" id="existing-practice"><span class="header-section-number">3.5</span> Existing Practice<a href="#existing-practice" class="self-link"></a></h2>
<p>There are three similar features in other languages that I’m aware
of.</p>
<p>Rust has <a href="https://doc.rust-lang.org/std/mem/union.MaybeUninit.html"><code class="sourceCode cpp">MaybeUninit<span class="op">&lt;</span>T<span class="op">&gt;</span></code></a>
which is similar to what’s described here as <code class="sourceCode cpp">std<span class="op">::</span>uninitialized<span class="op">&lt;</span>T<span class="op">&gt;</span></code>.</p>
<p>Kotlin has a <a href="https://kotlinlang.org/docs/properties.html#late-initialized-properties-and-variables"><code class="sourceCode cpp">lateinit var</code></a>
language feature, which is similar to some kind of language annotation
(although additionally allows for checking whether it has been
initialized, which the language feature would not provide).</p>
<p>D has the ability to initialize a variable to
<code class="sourceCode cpp"><span class="dt">void</span></code>, as in
<code class="sourceCode cpp"><span class="dt">int</span> x <span class="op">=</span> <span class="dt">void</span>;</code>
This leaves <code class="sourceCode cpp">x</code> uninitialized.
However, this feature only affects construction - not destruction. A
member <code class="sourceCode cpp">T<span class="op">[</span>N<span class="op">]</span> storage <span class="op">=</span> <span class="dt">void</span>;</code>
would leave the array uninitialized, but would destroy the whole array
in the destructor. So not really suitable for this particular
purpose.</p>
<h2 data-number="3.6" id="st.-louis-meeting-2024"><span class="header-section-number">3.6</span> St. Louis Meeting, 2024<a href="#st.-louis-meeting-2024" class="self-link"></a></h2>
<p>In <a href="https://github.com/cplusplus/papers/issues/1734#issuecomment-2195769496">St. Louis</a>,
we discussed a previous revision of this paper (<span class="citation" data-cites="P3074R3">[<a href="https://wg21.link/p3074r3" role="doc-biblioref">P3074R3</a>]</span>), specifically the <a href="#trivial-unions">trivial union</a> and <a href="#just-make-it-work">just make it work</a> designs. There, EWG
expressed a clear preference for “just make it work”:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>4</td>
<td>14</td>
<td>3</td>
<td>2</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>over <code class="sourceCode cpp">trivial <span class="kw">union</span></code>:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>0</td>
<td>3</td>
<td>13</td>
<td>4</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>So this paper proposes the more favorable design.</p>
<h2 data-number="3.7" id="just-to-double-check"><span class="header-section-number">3.7</span> Just to Double Check<a href="#just-to-double-check" class="self-link"></a></h2>
<p>During Core review in Wrocław, there was a desire to make it clear
that this proposal can change code that was previously ill-formed to
instead become undefined behavior:</p>
<div class="std">
<blockquote>
<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">union</span> U <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>string s;</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> f<span class="op">()</span> <span class="op">-&gt;</span> std<span class="op">::</span>string <span class="op">{</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>    U u;</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> u<span class="op">.</span>s;</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Status quo is that this program is ill-formed because
<code class="sourceCode cpp">U</code>’s constructor and destructor are
defined as deleted. With this proposal, they become trivial —
constructing <code class="sourceCode cpp">u</code> is valid but
<code class="sourceCode cpp">u<span class="op">.</span>s</code> is
uninitialized, which is then returned.</p>
<p>In practice, I don’t think this is a huge issue since users can
simply “fix” the issue of the deleted constructor and destructor by
adding <code class="sourceCode cpp">U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></code>
and <code class="sourceCode cpp"><span class="op">~</span>U<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></code>
— and now we’re back to the exact same problem anyway.</p>
<h2 data-number="3.8" id="constructordestructor-intention-matching"><span class="header-section-number">3.8</span> Constructor/Destructor
Intention Matching<a href="#constructordestructor-intention-matching" class="self-link"></a></h2>
<p>Consider:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U1 <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>string s <span class="op">=</span> <span class="st">&quot;this&quot;</span>;</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U2 <span class="op">{</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>    U2<span class="op">()</span> <span class="op">:</span> s<span class="op">(</span><span class="st">&quot;or that&quot;</span><span class="op">)</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>string s;</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U3 <span class="op">{</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>string s;</span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a>  U3<span class="op">*</span> next <span class="op">=</span> <span class="kw">nullptr</span>;</span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U4 <span class="op">{</span></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>string s;</span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> i;</span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>Now, <code class="sourceCode cpp">U4</code> is the simple case. Our
constructor is doing no initialization, so it’s reasonable that the
corresponding destructor also does nothing. But for the other three,
constructing one of these unions actually does something. So what should
the destructor look like?</p>
<p>Core in Wrocław suggested that the constructor and destructor should
really match. That is, if a
<code class="sourceCode cpp"><span class="kw">union</span></code> has a
variant with a non-trivial destructor and that union has non-trivial
default constructor (either by having a user-provided default
constructor or by having a default member initializer), then we should
retain the original rule and keep the deleted destructor. That makes
<code class="sourceCode cpp">U1</code>, <code class="sourceCode cpp">U2</code>,
and <code class="sourceCode cpp">U3</code> have a deleted destructor while
<code class="sourceCode cpp">U4</code> would have a trivial one.</p>
<p>I think that's overly strict. A good principle to follow, I think, is that this code:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">// for some union U</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>    U u;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Should either not compile (because the destructor is deleted — or
more boringly because <code class="sourceCode cpp">U</code> isn’t
default constructible) or be fine (because either we know the
initialization is okay and thus the destructor can be trivial, or we
forced the user to take care of it).</p>
<p>Thus the rule: the defaulted destructor for a union is defined as
deleted if either there is a user-provided default constructor or there
is a variant member with a default member initializer and that variant
member has a destructor that is either inaccessible, deleted, or non-trivial.
This rule makes <code class="sourceCode cpp">U1</code> have a deleted
destructor (default member initializer for a member that has a non-trivial
destructor), <code class="sourceCode cpp">U2</code> have a deleted destructor
(user-provided default constructor), but <code class="sourceCode cpp">U3</code>
and <code class="sourceCode cpp">U4</code> would both have a trivial destructor.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="proposal"><span class="header-section-number">4</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>This paper proposes to just <a href="#just-make-it-work">make it
work</a>. That is:</p>
<ul>
<li>The default constructor, absent default member initializers, is
always trivial. If the first alternative is an implicit-lifetime time,
it begins its lifetime and becomes the active alternative.</li>
<li>The defaulted destructor is deleted if either (a) the union has a
user-provided default constructor or (b) there exists a variant
alternative that has a default member initializer and that member’s
destructor is either deleted, inaccessible, or non-trivial. Otherwise, the destructor
is trivial.</li>
</ul>
<p>All other special members remain unchanged. The behavior for a few
examples looks like this:</p>
<div class="std">
<blockquote>
<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="co">// trivial default constructor (does not start lifetime of s)</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="co">// trivial destructor</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="co">// (status quo: deleted default constructor and destructor)</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U1 <span class="op">{</span> string s; <span class="op">}</span>;</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="co">// non-trivial default constructor</span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="co">// deleted destructor</span></span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a><span class="co">// (status quo: deleted destructor)</span></span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U2 <span class="op">{</span> string s <span class="op">=</span> <span class="st">&quot;hello&quot;</span>; <span class="op">}</span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a><span class="co">// trivial default constructor</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a><span class="co">// starts lifetime of s (just the array, not the elements!)</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a><span class="co">// trivial destructor</span></span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a><span class="co">// (status quo: deleted default constructor and destructor)</span></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U3 <span class="op">{</span> string s<span class="op">[</span><span class="dv">10</span><span class="op">]</span>; <span class="op">}</span></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a><span class="co">// non-trivial default constructor (initializes next)</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a><span class="co">// trivial destructor</span></span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a><span class="co">// (status quo: deleted destructor)</span></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a><span class="kw">union</span> U4 <span class="op">{</span> string s; U4<span class="op">*</span> next <span class="op">=</span> <span class="kw">nullptr</span>; <span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>Note that making it Just Work will change some code from ill-formed to
well-formed, but seems unlikely to change the meaning of any existing
already-valid code.</p>
<h2 data-number="4.1" id="implementation-experience"><span class="header-section-number">4.1</span> Implementation Experience<a href="#implementation-experience" class="self-link"></a></h2>
<p>I implemented this paper in <a href="https://github.com/llvm/llvm-project/compare/main...brevzin:llvm-project:p3074?expand=1">clang</a>,
it was not difficult. The clang tests that exist to check for the
existing
<code class="sourceCode cpp"><span class="kw">union</span></code>
behavior (i.e. that a union with an alternative with a non-trivial or no
default constructor has a deleted default constructor) now fail, as
expected. But something like this now passes (clang already implements
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
placement new — the status quo is that referencing <code class="sourceCode cpp"><span class="op">&amp;</span>s<span class="op">[</span><span class="dv">0</span><span class="op">]</span></code>
is ill-formed because <code class="sourceCode cpp">s</code> has not
began its lifetime):</p>
<div class="std">
<blockquote>
<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">constexpr</span> <span class="dt">int</span> f1<span class="op">()</span> <span class="op">{</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">union</span> <span class="op">{</span> <span class="dt">int</span> s<span class="op">[</span><span class="dv">4</span><span class="op">]</span>; <span class="op">}</span>;</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">new</span> <span class="op">(&amp;</span>s<span class="op">[</span><span class="dv">0</span><span class="op">])</span> <span class="dt">int</span><span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">new</span> <span class="op">(&amp;</span>s<span class="op">[</span><span class="dv">1</span><span class="op">])</span> <span class="dt">int</span><span class="op">(</span><span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">new</span> <span class="op">(&amp;</span>s<span class="op">[</span><span class="dv">2</span><span class="op">])</span> <span class="dt">int</span><span class="op">(</span><span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> s<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">+</span> s<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">+</span> s<span class="op">[</span><span class="dv">2</span><span class="op">]</span>;</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>f1<span class="op">()</span> <span class="op">==</span> <span class="dv">6</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
</div>
<p>I was able to compile Clang with this update successfully, which
wasn’t particularly surprising since this change is entirely about
making existing ill-formed code valid — and the Clang implementation is
already valid code.</p>
<h2 data-number="4.2" id="language-wording"><span class="header-section-number">4.2</span> Language Wording<a href="#language-wording" class="self-link"></a></h2>
<p>Change <span>11.4.5.2 <a href="https://wg21.link/class.default.ctor">[class.default.ctor]</a></span>/2-3.
<span class="ednote" style="color: #0000ff">[ Editor&#39;s note: The third
and fourth bullets can be removed because such cases become trivially
default constructible too ]</span></p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">2</a></span>
A defaulted default constructor for class
<code class="sourceCode cpp">X</code> is defined as deleted if <span class="addu"><code class="sourceCode cpp">X</code> is a non-union class
and</span>:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">(2.1)</a></span>
any non-static data member with no default member initializer
([class.mem]) is of reference type,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">(2.2)</a></span>
any non-variant non-static data member of const-qualified type (or
possibly multi-dimensional array thereof) with no
brace-or-equal-initializer is not const-default-constructible
([dcl.init]),</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">(2.3)</a></span>
<span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">X</code></span>
is a union and all of its variant members are of const-qualified type
(or possibly multi-dimensional array thereof),</del></span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">(2.4)</a></span>
<span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">X</code></span>
is a non-union class and all members of any anonymous union member are
of const-qualified type (or possibly multi-dimensional array
thereof)</del></span>,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">(2.5)</a></span>
any potentially constructed subobject, except for a non-static data
member with a brace-or-equal-initializer <span class="rm" style="color: #bf0303"><del>or a variant member of a union where another
non-static data member has a brace-or-equal-initializer</del></span>,
has class type <code class="sourceCode cpp">M</code> (or possibly
multi-dimensional array thereof) and overload resolution ([over.match])
as applied to find <code class="sourceCode cpp">M</code>’s corresponding
constructor either does not result in a usable candidate
([over.match.general]) <span class="rm" style="color: #bf0303"><del>or,
in the case of a variant member, selects a non-trivial
function,</del></span> or</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">3</a></span>
A default constructor <span class="addu">for a class
<code class="sourceCode cpp">X</code></span> is <em>trivial</em> if it
is not user-provided and if:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">(3.1)</a></span>
<span class="rm" style="color: #bf0303"><del>its class</del></span>
<span class="addu"><code class="sourceCode cpp">X</code></span> has no
virtual functions ([class.virtual]) and no virtual base classes
([class.mi]), and</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_9" id="pnum_9">(3.2)</a></span>
no non-static data member of <span class="rm" style="color: #bf0303"><del>its class</del></span> <span class="addu"><code class="sourceCode cpp">X</code></span> has a default
member initializer ([class.mem]), and</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">(3.3)</a></span>
all the direct base classes of <span class="rm" style="color: #bf0303"><del>its class</del></span> <span class="addu"><code class="sourceCode cpp">X</code></span> have trivial
default constructors, and</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">(3.4)</a></span>
<span class="addu">either <code class="sourceCode cpp">X</code> is a
union or</span> for all the non-static data members of <span class="rm" style="color: #bf0303"><del>its class</del></span> <span class="addu"><code class="sourceCode cpp">X</code></span> that are of
class type (or array thereof), each such class has a trivial default
constructor.</li>
</ul>
<p>Otherwise, the default constructor is <em>non-trivial</em>.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">4</a></span>
<span class="addu">If a default constructor of a union
<code class="sourceCode cpp">X</code> is trivial and the first variant
member, if any, of <code class="sourceCode cpp">X</code> has
implicit-lifetime type ([basic.types.general]), the default constructor
begins the lifetime of that member if it is not the active member of the
union. <span class="note"><span>[ <em>Note 1:</em> </span>It is already
the active member if <code class="sourceCode cpp">X</code> was
value-initialized.<span> — <em>end note</em> ]</span></span></span>
<span class="rm" style="color: #bf0303"><del>An</del></span> <span class="addu">Otherwise, an</span> implicitly-defined
([dcl.fct.def.default]) default constructor performs the set of
initializations of the class that would be performed by a user-written
default constructor for that class with no ctor-initializer
([class.base.init]) and an empty compound-statement.</p>
</blockquote>
</div>
<p>Change <span>11.4.7 <a href="https://wg21.link/class.dtor">[class.dtor]</a></span>/7-8:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">7</a></span>
A defaulted destructor for a class <code class="sourceCode cpp">X</code>
is defined as deleted if:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">(7.1)</a></span>
<span class="addu"><code class="sourceCode cpp">X</code> is a non-union
class and</span> any potentially constructed subobject has class type
<code class="sourceCode cpp">M</code> (or possibly multi-dimensional
array thereof) <span class="rm" style="color: #bf0303"><del>and</del></span> <span class="addu">where</span> <code class="sourceCode cpp">M</code> has a
destructor that is deleted or is inaccessible from the defaulted
destructor <span class="rm" style="color: #bf0303"><del>or, in the case
of a variant member, is non-trivial</del></span>,</li>
</ul>
<div class="addu">
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">(7.x)</a></span>
<code class="sourceCode cpp">X</code> is a union and either:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">(7.x.1)</a></span>
<code class="sourceCode cpp">X</code> has a user-provided default
constructor, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_17" id="pnum_17">(7.x.2)</a></span>
<code class="sourceCode cpp">X</code> has a variant member
<code class="sourceCode cpp">M</code> where
<code class="sourceCode cpp">M</code> has a default member initializer
and <code class="sourceCode cpp">M</code> has a destructor that is
deleted, inaccessible from the defaulted destructor, or
non-trivial,</li>
</ul></li>
</ul>
</div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_18" id="pnum_18">(7.2)</a></span>
or, for a virtual destructor, lookup of the non-array deallocation
function results in an ambiguity or in a function that is deleted or
inaccessible from the defaulted destructor.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_19" id="pnum_19">8</a></span>
A destructor <span class="addu">for a class
<code class="sourceCode cpp">X</code></span> is <em>trivial</em> if it
is not user-provided and if:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_20" id="pnum_20">(8.1)</a></span>
the destructor is not virtual,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_21" id="pnum_21">(8.2)</a></span>
all of the direct base classes of <span class="rm" style="color: #bf0303"><del>its class</del></span> <span class="addu"><code class="sourceCode cpp">X</code></span> have trivial
destructors, and</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_22" id="pnum_22">(8.3)</a></span>
<span class="addu">either <code class="sourceCode cpp">X</code> is a
union or</span> for all of the non-static data members of <span class="rm" style="color: #bf0303"><del>its class</del></span> <span class="addu"><code class="sourceCode cpp">X</code></span> that are of
class type (or array thereof), each such class has a trivial
destructor.</li>
</ul>
</blockquote>
</div>
<h2 data-number="4.3" id="library-wording"><span class="header-section-number">4.3</span> Library Wording<a href="#library-wording" class="self-link"></a></h2>
<p>While this paper was in flight, <span class="citation" data-cites="P0843R14">[<a href="https://wg21.link/p0843r14" role="doc-biblioref">P0843R14</a>]</span> was moved, which had to work
around the lack of ability to actually support non-trivial types during
constant evaluation. Since this paper now provides that, might as well
fix the library to account for the new functionality.</p>
<p>Strike <span>24.3.14.1 <a href="https://wg21.link/inplace.vector.overview">[inplace.vector.overview]</a></span>/4:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_23" id="pnum_23">3</a></span>
For any <code class="sourceCode cpp">N</code>, <code class="sourceCode cpp">inplace_vector<span class="op">&lt;</span>T, N<span class="op">&gt;</span>​<span class="op">::</span>​iterator</code>
and <code class="sourceCode cpp">inplace_vector<span class="op">&lt;</span>T, N<span class="op">&gt;</span>​<span class="op">::</span>​const_iterator</code>
meet the constexpr iterator requirements.</p>
<div class="rm" style="color: #bf0303">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_24" id="pnum_24">4</a></span>
For any <code class="sourceCode default">N&gt;0</code>, if
<code class="sourceCode default">is_trivial_v&lt;T&gt;</code> is
<code class="sourceCode default">false</code>, then no
<code class="sourceCode default">inplace_vector&lt;T, N&gt;</code>
member functions are usable in constant expressions.</p>
</div>
</blockquote>
</div>
<h2 data-number="4.4" id="feature-test-macro"><span class="header-section-number">4.4</span> Feature-Test Macro<a href="#feature-test-macro" class="self-link"></a></h2>
<p>Add a new macro to <span>15.11 <a href="https://wg21.link/cpp.predefined">[cpp.predefined]</a></span>:</p>
<div class="std ins">
<blockquote>
<div class="sourceCode" id="cb19"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>__cpp_trivial_union 2024XXL</span></code></pre></div>
</blockquote>
</div>
<p>And update the macro for
<code class="sourceCode cpp">inplace_vector</code> in <span>17.3.2 <a href="https://wg21.link/version.syn">[version.syn]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb20"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="st">- #define __cpp_lib_inplace_vector 202406L // also in &lt;inplace_vector&gt;</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="va">+ #define __cpp_lib_inplace_vector 2024XXL // also in &lt;inplace_vector&gt;</span></span></code></pre></div>
</div>
</blockquote>
</div>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">5</span>
References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-P0843R14" class="csl-entry" role="doc-biblioentry">
[P0843R14] Gonzalo Brito Gadeschi, Timur Doumler, Nevin Liber, David
Sankel. 2024-06-26. inplace_vector. <a href="https://wg21.link/p0843r14"><div class="csl-block">https://wg21.link/p0843r14</div></a>
</div>
<div id="ref-P2747R0" class="csl-entry" role="doc-biblioentry">
[P2747R0] Barry Revzin. 2022-12-17. Limited support for constexpr void*.
<a href="https://wg21.link/p2747r0"><div class="csl-block">https://wg21.link/p2747r0</div></a>
</div>
<div id="ref-P2747R2" class="csl-entry" role="doc-biblioentry">
[P2747R2] Barry Revzin. 2024-03-19. constexpr placement new. <a href="https://wg21.link/p2747r2"><div class="csl-block">https://wg21.link/p2747r2</div></a>
</div>
<div id="ref-P3074R0" class="csl-entry" role="doc-biblioentry">
[P3074R0] Barry Revzin. 2023-12-15. constexpr union lifetime. <a href="https://wg21.link/p3074r0"><div class="csl-block">https://wg21.link/p3074r0</div></a>
</div>
<div id="ref-P3074R1" class="csl-entry" role="doc-biblioentry">
[P3074R1] Barry Revzin. 2024-01-30. std::uninitialized&lt;T&gt;. <a href="https://wg21.link/p3074r1"><div class="csl-block">https://wg21.link/p3074r1</div></a>
</div>
<div id="ref-P3074R2" class="csl-entry" role="doc-biblioentry">
[P3074R2] Barry Revzin. 2024-02-13. std::uninitialized&lt;T&gt;. <a href="https://wg21.link/p3074r2"><div class="csl-block">https://wg21.link/p3074r2</div></a>
</div>
<div id="ref-P3074R3" class="csl-entry" role="doc-biblioentry">
[P3074R3] Barry Revzin. 2024-04-14. trivial union (was
std::uninitialized&lt;T&gt;). <a href="https://wg21.link/p3074r3"><div class="csl-block">https://wg21.link/p3074r3</div></a>
</div>
<div id="ref-P3074R4" class="csl-entry" role="doc-biblioentry">
[P3074R4] Barry Revzin. 2024-09-10. trivial unions (was
std::uninitialized&lt;T&gt;). <a href="https://wg21.link/p3074r4"><div class="csl-block">https://wg21.link/p3074r4</div></a>
</div>
</div>
</div>
</div>
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script></body>
</html>
