<!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="2025-06-03" />
  <title>Adjustments to Union Lifetime Rules</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;
}
td > div > 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.addu td pre { background-color: inherit; }
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.rm li {
text-decoration: line-through;
color: #000000;
}
div.std blockquote del, div.rm {
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">Adjustments to Union
Lifetime Rules</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3726R0 <a href="https://wg21.link/P3726">[Latest]</a> <a href="https://wg21.link/P3726/status">[Status]</a></td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-06-03</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>
      CWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.com</a>&gt;<br>
      Tomasz Kamiński<br>&lt;<a href="mailto:tomaszkam@gmail.com" class="email">tomaszkam@gmail.com</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a></li>
<li><a href="#proposal-1-fixing-when-implicit-lifetime-starts" id="toc-proposal-1-fixing-when-implicit-lifetime-starts"><span class="toc-section-number">2</span> Proposal 1: Fixing When Implicit
Lifetime Starts<span></span></a>
<ul>
<li><a href="#template-argument-equivalence" id="toc-template-argument-equivalence"><span class="toc-section-number">2.1</span>
Template-Argument-Equivalence<span></span></a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">2.2</span> Wording<span></span></a></li>
</ul></li>
<li><a href="#proposal-2-fixing-which-values-are-constituent-values" id="toc-proposal-2-fixing-which-values-are-constituent-values"><span class="toc-section-number">3</span> Proposal 2: Fixing Which Values are
Constituent Values<span></span></a></li>
<li><a href="#feature-test-macro" id="toc-feature-test-macro"><span class="toc-section-number">4</span> Feature-Test
Macro<span></span></a></li>
<li><a href="#acknowledgments" id="toc-acknowledgments"><span class="toc-section-number">5</span>
Acknowledgments<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">6</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">1</span>
Introduction<a href="#introduction" class="self-link"></a></h1>
<p><span class="title"><span class="citation" data-cites="P3074R7"><a href="https://wg21.link/p3074r7" role="doc-biblioref">[P3074R7] (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>))</a></span></span>
was adopted in Hagenberg. One of the goals of that paper was to make an
example like this work:</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> <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>    <span class="dt">size_t</span> size <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" 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-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="op">~</span>FixedVector<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>destroy<span class="op">(</span>storage, storage <span class="op">+</span> size<span class="op">)</span>;</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">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-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">::</span><span class="kw">new</span> <span class="op">(</span>storage <span class="op">+</span> size<span class="op">)</span> T<span class="op">(</span>v<span class="op">)</span>;</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span>size;</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-18"><a href="#cb1-18" 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-19"><a href="#cb1-19" 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-20"><a href="#cb1-20" 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-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> v<span class="op">.</span>size;</span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-24"><a href="#cb1-24" 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>That paper solved this problem by:</p>
<ol type="1">
<li>Making
<code class="sourceCode cpp"><span class="kw">union</span></code>s have
trivial default constructors and trivial destructors, by default,
and</li>
<li>Implicitly starting the lifetime of the first
<code class="sourceCode cpp"><span class="kw">union</span></code>
member, if that member has implicit-lifetime type.</li>
</ol>
<p>The first avoids pointless no-op empty constructors and destructors,
and the second would start the lifetime of the <code class="sourceCode cpp">T<span class="op">[</span>N<span class="op">]</span></code>
member — which we need in order for the placement new to be
well-defined. Which seemed to be a pretty nice thing, as the code just
works, without any complicated intervention.</p>
<p>However, there is an important principle in C++ language design that
Barry missed: we can’t have nice things because there are no nice
things. Richard Smith sent out this example:</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">union</span> U <span class="op">{</span> <span class="dt">int</span> a, b; <span class="op">}</span>;</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span>U u<span class="op">&gt;</span> <span class="kw">class</span> X <span class="op">{}</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> U make<span class="op">()</span> <span class="op">{</span> U u; <span class="cf">return</span> u; <span class="op">}</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> f<span class="op">(</span>X<span class="op">&lt;</span>make<span class="op">()&gt;)</span> <span class="op">{}</span></span></code></pre></div>
</blockquote>
</div>
<p>He pointed out that today this is valid because template argument of
<code class="sourceCode cpp">X</code> is a union object with no active
member. But with the <span class="citation" data-cites="P3074R7"><a href="https://wg21.link/p3074r7" role="doc-biblioref">[P3074R7]</a></span> changes, this:</p>
<ol type="1">
<li>Causes the union object to have an active member, and thus would
have to be mangled differently. That change makes this an ABI break
(although not all implementations mangle these cases differently, which
is probably a bug, so the potential damage of ABI break isn’t
tremendous)</li>
<li>Causes the example to fail to compile because it’s no longer a valid
template argument.</li>
</ol>
<p>The relevant rule here is is <span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span> which says
that:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">22</a></span>
A <em>constant expression</em> is either a glvalue core constant
expression that refers to an object or a non-immediate function, or a
prvalue core constant expression whose result object ([basic.lval])
satisfies the following constraints:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">(22.1)</a></span>
each constituent reference refers to an object or a non-immediate
function,</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">(22.2)</a></span>
no constituent value of scalar type is an indeterminate or erroneous
value ([basic.indet]),</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">(22.3)</a></span>
[…]</li>
</ul>
</blockquote>
</div>
<p>where, in that same section:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">2</a></span>
The <em>constituent values</em> of an object
<code class="sourceCode cpp"><em>o</em></code> are</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">(2.1)</a></span>
if <code class="sourceCode cpp"><em>o</em></code> has scalar type, the
value of <code class="sourceCode cpp"><em>o</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">(2.2)</a></span>
otherwise, the constituent values of any direct subobjects of
<code class="sourceCode cpp"><em>o</em></code> other than inactive union
members.</li>
</ul>
</blockquote>
</div>
<p>Note that inactive union members are excluded, but
active-yet-uninitialized union members are disallowed.</p>
<p>This is also a problem because the original goal of the paper was to
make types like <code class="sourceCode cpp">std<span class="op">::</span>inplace_vector</code>
completely usable at compile-time, and this rule (even separate from
<span class="citation" data-cites="P3074R7"><a href="https://wg21.link/p3074r7" role="doc-biblioref">[P3074R7]</a></span>) makes that impossible:</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">constexpr</span> std<span class="op">::</span>inplace_vector<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">4</span><span class="op">&gt;</span> v <span class="op">=</span> <span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>A “normal” implementation would have <code class="sourceCode cpp"><span class="kw">union</span> <span class="op">{</span> <span class="dt">int</span> storage<span class="op">[</span><span class="dv">4</span><span class="op">]</span>; <span class="op">}</span></code>,
of which the first two elements are initialized but the last two are
not. And thus have indeterminate value, so this isn’t a valid constant
expression. For
<code class="sourceCode cpp"><span class="dt">int</span></code>
specifically (and trivial types more broadly), this is fixable by having
the implementation simply have a <code class="sourceCode cpp"><span class="dt">int</span> storage<span class="op">[</span><span class="dv">4</span><span class="op">]</span>;</code>
instead and initialize all the objects — since that’s free. But for
types that either aren’t trivially default constructible or aren’t
trivially destructible, that’s not an option, and that really shouldn’t
be the limiting factor of whether you can create
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
variables (or non-type template arguments) of such types.</p>
<p>We’re hoping to fix both of those issues in this paper, with two
fairly independent fixes.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="proposal-1-fixing-when-implicit-lifetime-starts"><span class="header-section-number">2</span> Proposal 1: Fixing When Implicit
Lifetime Starts<a href="#proposal-1-fixing-when-implicit-lifetime-starts" class="self-link"></a></h1>
<p><span class="citation" data-cites="P3074R7"><a href="https://wg21.link/p3074r7" role="doc-biblioref">[P3074R7]</a></span> added this wording to
<span>11.4.5.2 <a href="https://wg21.link/class.default.ctor">[class.default.ctor]</a></span>:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">4</a></span>
<span class="addu">If a default constructor of a union-like class
<code class="sourceCode cpp">X</code> is trivial, then for each union
<code class="sourceCode cpp">U</code> that is either
<code class="sourceCode cpp">X</code> or an anonymous union member of
<code class="sourceCode cpp">X</code>, if the first variant member, if
any, of <code class="sourceCode cpp">U</code> has implicit-lifetime type
([basic.types.general]), the default constructor of
<code class="sourceCode cpp">X</code> begins the lifetime of that member
if it is not the active member of its union. <span class="note"><span>[ <em>Note 1:</em> </span>It is already the active
member if <code class="sourceCode cpp">U</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>That wording needs to be reverted. The default constructor will no
longer start lifetimes implicitly.</p>
<p>Instead, we allow placement new on an aggregate element to start the
lifetime of the aggregate. That is, given the above implementation:</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">typename</span> T, <span class="dt">size_t</span> N<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> FixedVector <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-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="cb4-4"><a href="#cb4-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="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">constexpr</span> FixedVector<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" 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="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>destroy<span class="op">(</span>storage, storage <span class="op">+</span> size<span class="op">)</span>;</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-12"><a href="#cb4-12" 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="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">::</span><span class="kw">new</span> <span class="op">(</span>storage <span class="op">+</span> size<span class="op">)</span> T<span class="op">(</span>v<span class="op">)</span>;</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span>size;</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-18"><a href="#cb4-18" 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="cb4-19"><a href="#cb4-19" 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="cb4-20"><a href="#cb4-20" 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="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> v<span class="op">.</span>size;</span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-24"><a href="#cb4-24" 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 will work for the following reason:</p>
<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong><span class="citation" data-cites="P3074R7"><a href="https://wg21.link/p3074r7" role="doc-biblioref">[P3074R7]</a></span></strong>
</div></th>
<th><div style="text-align:center">
<strong>This Paper</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Default constructor starts lifetime of array (but not any
elements)</td>
<td>Default constructor does not start any lifetime</td>
</tr>
<tr class="even">
<td>The array is already within lifetime and is the active member</td>
<td>The act of placement-new onto the array starts the lifetime of the
array and makes it the active member</td>
</tr>
<tr class="odd">
<td>Placement new is well-defined</td>
<td>Placement new is well-defined</td>
</tr>
</tbody>
</table>
<p>We get to a well-defined state through a different route, but we
still get to a well-defined state with reasonable code. Importantly, we
don’t change the behavior of existing code (as in Richard’s example)
since no lifetimes are implicitly created, and here we’re allowing a
placement new that is invalid today to instead also start lifetimes.</p>
<h2 data-number="2.1" id="template-argument-equivalence"><span class="header-section-number">2.1</span> Template-Argument-Equivalence<a href="#template-argument-equivalence" class="self-link"></a></h2>
<p>One of the consequences of the above proposal is what happens when we
compare objects that should be equivalent but got there with different
paths:</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="co">// see next section for making this work, but assume it does for now</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> v1 <span class="op">=</span> FixedVector<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">4</span><span class="op">&gt;()</span>;</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> v2 <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> v <span class="op">=</span> FixedVector<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">4</span><span class="op">&gt;()</span>;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>  v<span class="op">.</span>push_back<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  v<span class="op">.</span>pop_back<span class="op">()</span>;</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> v;</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>I didn’t show
<code class="sourceCode cpp">pop_back<span class="op">()</span></code>
in the above implementation, but let’s say it just does <code class="sourceCode cpp">storage<span class="op">[--</span>size<span class="op">].~</span>T<span class="op">()</span></code>.
What can we say about <code class="sourceCode cpp">v1</code> and
<code class="sourceCode cpp">v2</code>? Well, they’re both empty
vectors, so they compare equal. However, they’re in different
states:</p>
<ul>
<li><code class="sourceCode cpp">v1</code>’s anonymous union has no
active member, because we never started any lifetimes.</li>
<li><code class="sourceCode cpp">v2</code>’s anonymous union does have
an active member <code class="sourceCode cpp">storage</code>, with no
elements within lifetime.</li>
</ul>
<p>Those wouldn’t compare template-argument-equivalent, so <code class="sourceCode cpp">X<span class="op">&lt;</span>v1<span class="op">&gt;</span></code>
and <code class="sourceCode cpp">X<span class="op">&lt;</span>v2<span class="op">&gt;</span></code>
would be different types (for suitable template
<code class="sourceCode cpp">X</code>). This isn’t a very serious
concern right now, since <code class="sourceCode cpp">FixedVector</code>
isn’t a structural type and that will remain true in C++26. But
nevertheless, there is an easy way to ensure equivalence: by adding a
new member to the union:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> FixedVector <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Empty <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">union</span> <span class="op">{</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>      Empty empty <span class="op">=</span> <span class="op">{}</span>;</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>      T storage<span class="op">[</span>N<span class="op">]</span>;</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb6-8"><a href="#cb6-8" 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="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-10"><a href="#cb6-10" 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="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-12"><a href="#cb6-12" 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="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>destroy<span class="op">(</span>storage, storage <span class="op">+</span> size<span class="op">)</span>;</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-16"><a href="#cb6-16" 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="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>        <span class="op">::</span><span class="kw">new</span> <span class="op">(</span>storage <span class="op">+</span> size<span class="op">)</span> T<span class="op">(</span>v<span class="op">)</span>;</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>        <span class="op">++</span>size;</span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> pop_back<span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">void</span> <span class="op">{</span></span>
<span id="cb6-22"><a href="#cb6-22" aria-hidden="true" tabindex="-1"></a>        storage<span class="op">[--</span>size<span class="op">].~</span>T<span class="op">()</span>;</span>
<span id="cb6-23"><a href="#cb6-23" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span>size <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-24"><a href="#cb6-24" aria-hidden="true" tabindex="-1"></a>            empty <span class="op">=</span> Empty<span class="op">()</span>;</span>
<span id="cb6-25"><a href="#cb6-25" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb6-26"><a href="#cb6-26" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb6-27"><a href="#cb6-27" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>Now, <code class="sourceCode cpp">v1</code> and
<code class="sourceCode cpp">v2</code> are in the same state: the active
member of the union is <code class="sourceCode cpp">empty</code>.</p>
<h2 data-number="2.2" id="wording"><span class="header-section-number">2.2</span> Wording<a href="#wording" class="self-link"></a></h2>
<p>Revert the change in [class.default.ctor]/4:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_9" id="pnum_9">4</a></span>
<span class="rm" style="color: #bf0303"><del>If a default constructor of
a union-like class
<span><code class="sourceCode default">X</code></span> is trivial, then
for each union <span><code class="sourceCode default">U</code></span>
that is either <span><code class="sourceCode default">X</code></span> or
an anonymous union member of
<span><code class="sourceCode default">X</code></span>, if the first
variant member, if any, of
<span><code class="sourceCode default">U</code></span> has
implicit-lifetime type ([basic.types.general]), the default constructor
of <span><code class="sourceCode default">X</code></span> begins the
lifetime of that member if it is not the active member of its union.
<span class="note"><span>[ <em>Note 1:</em> </span>It is already the
active member if <span><code class="sourceCode default">U</code></span>
was value-initialized.<span> — <em>end
note</em> ]</span></span></del></span> <span class="addu">An</span>
<span class="rm" style="color: #bf0303"><del>Otherwise, an</del></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.5.1 <a href="https://wg21.link/class.union.general">[class.union.general]</a></span>/5:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">5</a></span>
When <span class="addu">either</span></p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">(5.a)</a></span>
the left operand of an assignment operator involves a member access
expression ([expr.ref]) that nominates a union member <span class="addu">or</span></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">(5.b)</a></span>
<span class="addu">the placement argument to a
<code class="sourceCode cpp"><em>new-expression</em></code> ([expr.new])
that is a non-allocating form ([new.delete.placement]) involves such a
member access expression,</span></li>
</ul>
<p>it may begin the lifetime of that union member, as described
below.</p>
<p>For an expression <code class="sourceCode cpp">E</code>, define the
set <code class="sourceCode cpp"><em>S</em><span class="op">(</span>E<span class="op">)</span></code>
of subexpressions of <code class="sourceCode cpp">E</code> as
follows:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">(5.1)</a></span>
If <code class="sourceCode cpp">E</code> is of the form
<code class="sourceCode cpp">A<span class="op">.</span>B</code>, <code class="sourceCode cpp"><em>S</em><span class="op">(</span>E<span class="op">)</span></code>
contains the elements of <code class="sourceCode cpp"><em>S</em><span class="op">(</span>A<span class="op">)</span></code>,
and also contains
<code class="sourceCode cpp">A<span class="op">.</span>B</code> if
<code class="sourceCode cpp">B</code> names a union member of a
non-class, non-array type, or of a class type with a trivial default
constructor that is not deleted, or an array of such types.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">(5.2)</a></span>
If <code class="sourceCode cpp">E</code> is of the form <code class="sourceCode cpp">A<span class="op">[</span>B<span class="op">]</span></code>
and is interpreted as a built-in array subscripting operator, <code class="sourceCode cpp"><em>S</em><span class="op">(</span>E<span class="op">)</span></code>
is <code class="sourceCode cpp"><em>S</em><span class="op">(</span>A<span class="op">)</span></code>
if <code class="sourceCode cpp">A</code> is of array type, <code class="sourceCode cpp"><em>S</em><span class="op">(</span>B<span class="op">)</span></code>
if <code class="sourceCode cpp">B</code> is of array type, and empty
otherwise.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">(5.3)</a></span>
Otherwise, <code class="sourceCode cpp"><em>S</em><span class="op">(</span>E<span class="op">)</span></code>
is empty.</li>
</ul>
<p>In an assignment expression of the form
<code class="sourceCode cpp">E1 <span class="op">=</span> E2</code> that
uses either the built-in assignment operator ([expr.assign]) or a
trivial assignment operator ([class.copy.assign]), for each element
<code class="sourceCode cpp">X</code> of <code class="sourceCode cpp"><em>S</em><span class="op">(</span>E1<span class="op">)</span></code>
and each anonymous union member <code class="sourceCode cpp">X</code>
([class.union.anon]) that is a member of a union and has such an element
as an immediate subobject (recursively), if modification of
<code class="sourceCode cpp">X</code> would have undefined behavior
under [basic.life], an object of the type of
<code class="sourceCode cpp">X</code> is implicitly created in the
nominated storage; no initialization is performed and the beginning of
its lifetime is sequenced after the value computation of the left and
right operands and before the assignment.</p>
<div class="addu">
<p>For an expression <code class="sourceCode cpp">E</code>, define the
set <code class="sourceCode cpp"><em>P</em><span class="op">(</span>E<span class="op">)</span></code>
of subexpressions of <code class="sourceCode cpp">E</code> as
follows:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">(5.4)</a></span>
If <code class="sourceCode cpp">E</code> is of the form <code class="sourceCode cpp"><span class="op">&amp;</span>A<span class="op">[</span>B<span class="op">]</span></code>,
<code class="sourceCode cpp">E</code> is interpreted as a built-in
address operator, and <code class="sourceCode cpp">A<span class="op">[</span>B<span class="op">]</span></code>
is interpreted as a built-in array subscripting operator, then <code class="sourceCode cpp"><em>P</em><span class="op">(</span>E<span class="op">)</span></code>
is <code class="sourceCode cpp">A</code> if
<code class="sourceCode cpp">A</code> is of array type,
<code class="sourceCode cpp">B</code> if
<code class="sourceCode cpp">B</code> is of array type, and empty
otherwise.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_17" id="pnum_17">(5.5)</a></span>
If <code class="sourceCode cpp">E</code> has pointer type and is either
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_18" id="pnum_18">(5.5.1)</a></span>
of the form
<code class="sourceCode cpp">A <span class="op">+</span> B</code> and is
interpreted as a built-in addition operator or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_19" id="pnum_19">(5.5.2)</a></span>
of the form
<code class="sourceCode cpp">A <span class="op">-</span> B</code> and is
interpreted as a built-in subtraction operator,</li>
</ul>
then <code class="sourceCode cpp"><em>P</em><span class="op">(</span>E<span class="op">)</span></code>
is <code class="sourceCode cpp">A</code> if
<code class="sourceCode cpp">A</code> is of array type,
<code class="sourceCode cpp">B</code> if
<code class="sourceCode cpp">B</code> is of array type, and the union of
<code class="sourceCode cpp"><em>P</em><span class="op">(</span>A<span class="op">)</span></code>
and <code class="sourceCode cpp"><em>P</em><span class="op">(</span>B<span class="op">)</span></code>
otherwise.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_20" id="pnum_20">(5.6)</a></span>
Otherwise, <code class="sourceCode cpp"><em>P</em><span class="op">(</span>E<span class="op">)</span></code>
is empty.</li>
</ul>
<p>In a <code class="sourceCode cpp"><em>new-expression</em></code> with
a <code class="sourceCode cpp"><em>new-placement</em></code> of the form
<code class="sourceCode cpp"><span class="op">(</span>E<span class="op">)</span></code>
that uses a non-allocating form ([new.delete.placement]), for each
element <code class="sourceCode cpp">X</code> of <code class="sourceCode cpp"><em>P</em><span class="op">(</span>E<span class="op">)</span></code>
that names a union member and each anonymous union member
<code class="sourceCode cpp">X</code> that is a member of a union and
has such an element as an immediate subobject (recursively), if
<code class="sourceCode cpp">X</code> is not within its lifetime, the
lifetime of an object of the type of
<code class="sourceCode cpp">X</code> is started in the nominated
storage; no subobjects are created and the beginning of its lifetime is
sequenced immediately before the value computation of
<code class="sourceCode cpp">E</code>.</p>
</div>
<p><span class="note"><span>[ <em>Note 2:</em> </span>This ends the
lifetime of the previously-active member of the union, if any
([basic.life]).<span> — <em>end note</em> ]</span></span></p>
</blockquote>
</div>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="proposal-2-fixing-which-values-are-constituent-values"><span class="header-section-number">3</span> Proposal 2: Fixing Which Values
are Constituent Values<a href="#proposal-2-fixing-which-values-are-constituent-values" class="self-link"></a></h1>
<p>The current rule for constituent values is, from <span>7.7 <a href="https://wg21.link/expr.const">[expr.const]</a></span>/2:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_21" id="pnum_21">2</a></span>
The <em>constituent values</em> of an object
<code class="sourceCode cpp"><em>o</em></code> are</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_22" id="pnum_22">(2.1)</a></span>
if <code class="sourceCode cpp"><em>o</em></code> has scalar type, the
value of <code class="sourceCode cpp"><em>o</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_23" id="pnum_23">(2.2)</a></span>
otherwise, the constituent values of any direct subobjects of
<code class="sourceCode cpp"><em>o</em></code> other than inactive union
members.</li>
</ul>
</blockquote>
</div>
<p>As mentioned earlier, this means that if we have a <code class="sourceCode cpp"><span class="kw">union</span> <span class="op">{</span> T storage<span class="op">[</span><span class="dv">4</span><span class="op">]</span>; <span class="op">}</span></code>
then either there are no constituent values (if
<code class="sourceCode cpp">storage</code> is inactive) or we consider
all of the <code class="sourceCode cpp">T</code>s as constituent values
(even if we only constructed the first two). So we’ll need to loosen
this rule to permit objects with union members to be more usable as
constant expressions.</p>
<p>For the <code class="sourceCode cpp">FixedVector</code> (aka
<code class="sourceCode cpp">static_vector</code> aka
<code class="sourceCode cpp">inplace_vector</code>) example, we really
only need to allow “holes” at the end of the array. But if we want to
support a different container, that is more bidirectional and supports
cheap <code class="sourceCode cpp">push_front</code> and
<code class="sourceCode cpp">pop_front</code>, we will also want to
support “holes” at the front of the array. So for simplicity, we’re
proposing to support holes <em>anywhere</em> in the array. Note that
we’re still not proposing nice syntax for actually constructing such an
array with holes. Richard on the reflector had suggested a strawperson
syntax:</p>
<div class="std">
<blockquote>
<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="co">// short array initializer:</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="co">// initializes arr[0] and arr[1],</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="co">// does not start lifetime of rest</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> arr<span class="op">[</span><span class="dv">42</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>a, b, <span class="dt">short</span><span class="op">}</span>;</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="co">// in std::allocator&lt;T&gt;::allocate:</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="cf">return</span> <span class="kw">new</span> <span class="op">(</span>ptr<span class="op">)</span> T<span class="op">[</span>n<span class="op">]{</span><span class="dt">short</span><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>I don’t think we strictly need to solve that problem right now, but
at least we can put in the groundwork for supporting it in the
future.</p>
<p>Until then, we’re proposing something like this change to <span>7.7
<a href="https://wg21.link/expr.const">[expr.const]</a></span>:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_24" id="pnum_24">2</a></span>
The <em>constituent values</em> of an object
<code class="sourceCode cpp"><em>o</em></code> are</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_25" id="pnum_25">(2.1)</a></span>
if <code class="sourceCode cpp"><em>o</em></code> has scalar type, the
value of <code class="sourceCode cpp"><em>o</em></code>;</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_26" id="pnum_26">(2.2)</a></span>
otherwise, the constituent values of any direct subobjects of
<code class="sourceCode cpp"><em>o</em></code> other than inactive union
<span class="rm" style="color: #bf0303"><del>members</del></span> <span class="addu">subobjects (see below)</span>.</li>
</ul>
<p>The <em>constituent references</em> of an object
<code class="sourceCode cpp"><em>o</em></code> are</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_27" id="pnum_27">(2.3)</a></span>
any direct members of <code class="sourceCode cpp"><em>o</em></code>
that have reference type, and</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_28" id="pnum_28">(2.4)</a></span>
the constituent references of any direct subobjects of
<code class="sourceCode cpp"><em>o</em></code> other than inactive union
<span class="rm" style="color: #bf0303"><del>members</del></span> <span class="addu">subobjects</span>.</li>
</ul>
<div class="addu">
<p>An <em>inactive union subobject</em> is either:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_29" id="pnum_29">(2.5)</a></span>
an inactive union member or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_30" id="pnum_30">(2.6)</a></span>
an element <code class="sourceCode cpp"><em>A</em></code> of an array
member of a union where <code class="sourceCode cpp"><em>A</em></code>
is not within its lifetime.</li>
</ul>
<div class="example">
<span>[ <em>Example 1:</em> </span>
<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">struct</span> A <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> X <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>        <span class="dt">int</span> i;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>        <span class="dt">int</span> j;</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> Y <span class="op">{</span></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>        X x1;</span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>        X x2;</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">union</span> <span class="op">{</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>        <span class="dt">int</span> i;</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>        <span class="dt">int</span> arr<span class="op">[</span><span class="dv">4</span><span class="op">]</span>;</span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>        Y y;</span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> A v1;       <span class="co">// ok, no constituent values</span></span>
<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> A v2<span class="op">{.</span>i<span class="op">=</span><span class="dv">1</span><span class="op">}</span>; <span class="co">// ok, the constituent values are {v2.i}</span></span>
<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> A v3 <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a>    A a;</span>
<span id="cb8-23"><a href="#cb8-23" aria-hidden="true" tabindex="-1"></a>    <span class="kw">new</span> <span class="op">(&amp;</span>a<span class="op">.</span>arr<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">1</span><span class="op">)</span>;</span>
<span id="cb8-24"><a href="#cb8-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">new</span> <span class="op">(&amp;</span>a<span class="op">.</span>arr<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">2</span><span class="op">)</span>;</span>
<span id="cb8-25"><a href="#cb8-25" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> a;</span>
<span id="cb8-26"><a href="#cb8-26" aria-hidden="true" tabindex="-1"></a><span class="op">}()</span>;                 <span class="co">// ok, the constituent values are {v3.arr[1], v3.arr[2]}</span></span>
<span id="cb8-27"><a href="#cb8-27" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> A v4 <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb8-28"><a href="#cb8-28" aria-hidden="true" tabindex="-1"></a>    A a;</span>
<span id="cb8-29"><a href="#cb8-29" aria-hidden="true" tabindex="-1"></a>    a<span class="op">.</span>y<span class="op">.</span>x1<span class="op">.</span>i <span class="op">=</span> <span class="dv">1</span>;</span>
<span id="cb8-30"><a href="#cb8-30" aria-hidden="true" tabindex="-1"></a>    a<span class="op">.</span>y<span class="op">.</span>x2<span class="op">.</span>j <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb8-31"><a href="#cb8-31" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> a;</span>
<span id="cb8-32"><a href="#cb8-32" aria-hidden="true" tabindex="-1"></a><span class="op">}()</span>;                 <span class="co">// error: the constituent values include v4.y.x1.j and v4.y.x2.i</span></span>
<span id="cb8-33"><a href="#cb8-33" aria-hidden="true" tabindex="-1"></a><span class="co">//                   // which have erroneous value</span></span></code></pre></div>
<span> — <em>end example</em> ]</span>
</div>
</div>
</blockquote>
</div>
<p>And extend the template-argument-equivalent rules to understand this,
in <span>13.6 <a href="https://wg21.link/temp.type">[temp.type]</a></span>:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_31" id="pnum_31">2</a></span>
Two values are <em>template-argument-equivalent</em> if they are of the
same type and</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_32" id="pnum_32">(2.1)</a></span>
[…]</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_33" id="pnum_33">(2.8)</a></span>
they are of array type and their corresponding elements are <span class="addu">either both within lifetime and</span>
template-argument-equivalent <span class="addu">or both not within their
lifetime</span>, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_34" id="pnum_34">(2.9)</a></span>
[…]</li>
</ul>
</blockquote>
</div>
<p>That fix ensures that:</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">constexpr</span> std<span class="op">::</span>inplace_vector<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">4</span><span class="op">&gt;</span> v <span class="op">=</span> <span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">}</span>;</span></code></pre></div>
</blockquote>
</div>
<p>is a valid constexpr variable if the implementation uses a <code class="sourceCode cpp"><span class="kw">union</span> <span class="op">{</span> <span class="dt">int</span> storage<span class="op">[</span><span class="dv">4</span><span class="op">]</span>; <span class="op">}</span></code>
to hold the data, because we would only consider the first two elements
of <code class="sourceCode cpp">storage</code> as constituent values —
the fact that the last two elements are uninitialized no longer counts
against us when we consider whether
<code class="sourceCode cpp">v</code> is a valid result of a constant
expression.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="feature-test-macro"><span class="header-section-number">4</span>
Feature-Test Macro<a href="#feature-test-macro" class="self-link"></a></h1>
<p>And bump the feature-test macro added by <span class="citation" data-cites="P3074R7"><a href="https://wg21.link/p3074r7" role="doc-biblioref">[P3074R7]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb10"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="st">- __cpp_trivial_union 202502L</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="va">+ __cpp_trivial_union 2025XXL</span></span></code></pre></div>
</div>
</blockquote>
</div>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="acknowledgments"><span class="header-section-number">5</span>
Acknowledgments<a href="#acknowledgments" class="self-link"></a></h1>
<p>Thank you to Richard Smith for bringing the issue to our attention
and for all the helpful suggestions.</p>
<h1 data-number="6" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">6</span>
References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-P3074R7" class="csl-entry" role="doc-biblioentry">
[P3074R7] Barry Revzin. 2025-02-14. 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>).
<a href="https://wg21.link/p3074r7"><div class="csl-block">https://wg21.link/p3074r7</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
