<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>P3233R0: Issues with P2786 ("Trivial Relocatability For C++26")</title>
<style data-fill-with="stylesheet">/******************************************************************************
 *                   Style sheet for the W3C specifications                   *
 *
 * Special classes handled by this style sheet include:
 *
 * Indices
 *   - .toc for the Table of Contents (<ol class="toc">)
 *     + <span class="secno"> for the section numbers
 *   - #toc for the Table of Contents (<nav id="toc">)
 *   - ul.index for Indices (<a href="#ref">term</a><span>, in § N.M</span>)
 *   - table.index for Index Tables (e.g. for properties or elements)
 *
 * Structural Markup
 *   - table.data for general data tables
 *     -> use 'scope' attribute, <colgroup>, <thead>, and <tbody> for best results !
 *     -> use <table class='complex data'> for extra-complex tables
 *     -> use <td class='long'> for paragraph-length cell content
 *     -> use <td class='pre'> when manual line breaks/indentation would help readability
 *   - dl.switch for switch statements
 *   - ol.algorithm for algorithms (helps to visualize nesting)
 *   - .figure and .caption (HTML4) and figure and figcaption (HTML5)
 *     -> .sidefigure for right-floated figures
 *   - ins/del
 *     -> ins/del.c### for candidate and proposed changes (amendments)
 *
 * Code
 *   - pre and code
 *
 * Special Sections
 *   - .note       for informative notes             (div, p, span, aside, details)
 *   - .example    for informative examples          (div, p, pre, span)
 *   - .issue      for issues                        (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *   - .correction for "candidate corrections"       (div, aside, details, section)
 *   - .addition   for "candidate additions"         (div, aside, details, section)
 *   - .correction.proposed for "proposed corrections" (div, aside, details, section)
 *   - .addition.proposed   for "proposed additions"   (div, aside, details, section)
 *
 * Definition Boxes
 *   - pre.def   for WebIDL definitions
 *   - table.def for tables that define other entities (e.g. CSS properties)
 *   - dl.def    for definition lists that define other entitles (e.g. HTML elements)
 *
 * Numbering
 *   - .secno for section numbers in .toc and headings (<span class='secno'>3.2</span>)
 *   - .marker for source-inserted example/figure/issue numbers (<span class='marker'>Issue 4</span>)
 *   - ::before styled for CSS-generated issue/example/figure numbers:
 *     -> Documents wishing to use this only need to add
 *        figcaption::before,
 *        .caption::before { content: "Figure "  counter(figure) " ";  }
 *        .example::before { content: "Example " counter(example) " "; }
 *        .issue::before   { content: "Issue "   counter(issue) " ";   }
 *
 * Header Stuff (ignore, just don't conflict with these classes)
 *   - .head for the header
 *   - .copyright for the copyright
 *
 * Outdated warning for old specs
 *
 * Miscellaneous
 *   - .overlarge for things that should be as wide as possible, even if
 *     that overflows the body text area. This can be used on an item or
 *     on its container, depending on the effect desired.
 *     Note that this styling basically doesn't help at all when printing,
 *     since A4 paper isn't much wider than the max-width here.
 *     It's better to design things to fit into a narrower measure if possible.
 *
 *   - js-added ToC jump links (see fixup.js)
 *
 ******************************************************************************/

/* color variables included separately for reliability */

/******************************************************************************/
/*                                    Body                                    */
/******************************************************************************/

	html {
	}

	body {
		counter-reset: example figure issue;

		/* Layout */
		max-width: 50em;			  /* limit line length to 50em for readability   */
		margin: 0 auto;				/* center text within page                    */
		padding: 1.6em 1.5em 2em 50px; /* assume 16px font size for downlevel clients */
		padding: 1.6em 1.5em 2em calc(26px + 1.5em); /* leave space for status flag    */

		/* Typography */
		line-height: 1.5;
		font-family: sans-serif;
		widows: 2;
		orphans: 2;
		word-wrap: break-word;
		overflow-wrap: break-word;
		hyphens: auto;

		color: black;
		color: var(--text);
		background: white top left fixed no-repeat;
		background: var(--bg) top left fixed no-repeat;
		background-size: 25px auto;
	}


/******************************************************************************/
/*                         Front Matter & Navigation                          */
/******************************************************************************/

/** Header ********************************************************************/

	div.head { margin-bottom: 1em; }
	div.head hr { border-style: solid; }

	div.head h1 {
		font-weight: bold;
		margin: 0 0 .1em;
		font-size: 220%;
	}

	div.head h2 { margin-bottom: 1.5em;}

/** W3C Logo ******************************************************************/

	.head .logo {
		float: right;
		margin: 0.4rem 0 0.2rem .4rem;
	}

	.head img[src*="logos/W3C"] {
		display: block;
		border: solid #1a5e9a;
		border: solid var(--logo-bg);
		border-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		background: var(--logo-bg);
		color: white;
		color: var(--logo-text);
		font-weight: bold;
	}

	.head a:hover > img[src*="logos/W3C"],
	.head a:focus > img[src*="logos/W3C"] {
		opacity: .8;
	}

	.head a:active > img[src*="logos/W3C"] {
		background: #c00;
		background: var(--logo-active-bg);
		border-color: #c00;
		border-color: var(--logo-active-bg);
	}

	/* see also additional rules in Link Styling section */

/** Copyright *****************************************************************/

	p.copyright,
	p.copyright small { font-size: small; }

/** Back to Top / ToC Toggle **************************************************/

	@media print {
		#toc-nav {
			display: none;
		}
	}
	@media not print {
		#toc-nav {
			position: fixed;
			z-index: 3;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

			height: 1.33em;
			padding: .1em 0.3em;
			margin: 0;

			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;

			color: #707070;
			color: var(--tocnav-normal-text);
			background: white;
			background: var(--tocnav-normal-bg);
		}
		#toc-nav > a:hover,
		#toc-nav > a:focus {
			color: black;
			color: var(--tocnav-hover-text);
			background: #f8f8f8;
			background: var(--tocnav-hover-bg);
		}
		#toc-nav > a:active {
			color: #c00;
			color: var(--tocnav-active-text);
			background: white;
			background: var(--tocnav-active-bg);
		}

		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		/* statusbar gets in the way on keyboard focus; remove once browsers fix */
		#toc-nav > a[href="#toc"]:not(:hover):focus:last-child {
			padding-bottom: 1.5rem;
		}

		#toc-nav:not(:hover) > a:not(:focus) > span + span {
			/* Ideally this uses :focus-within on #toc-nav */
			display: none;
		}
		#toc-nav > a > span + span {
			padding-right: 0.2em;
		}
	}

/** ToC Sidebar ***************************************************************/

	/* Floating sidebar */
	@media screen {
		body.toc-sidebar #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			max-width: 80%;
			max-width: calc(100% - 2em - 26px);
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			color: black;
			color: var(--tocsidebar-text);
			background: inherit;
			background-color: #f7f8f9;
			background-color: var(--tocsidebar-bg);
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
			box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset;
		}
		body.toc-sidebar #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
			color: var(--tocsidebar-heading-text);
		}
		body.toc-sidebar #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	/* Hide main scroller when only the ToC is visible anyway */
	@media screen and (max-width: 28em) {
		body.toc-sidebar {
			overflow: hidden;
		}
	}

	/* Sidebar with its own space */
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			color: black;
			color: var(--tocsidebar-text);
			background: inherit;
			background-color: #f7f8f9;
			background-color: var(--tocsidebar-bg);
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
			box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset;
		}
		body:not(.toc-inline) #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
			color: var(--tocsidebar-heading-text);
		}

		body:not(.toc-inline) {
			padding-left: 29em;
		}
		/* See also Overflow section at the bottom */

		body:not(.toc-inline) #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) {
			margin: 0 4em;
		}
	}

/******************************************************************************/
/*                                Sectioning                                  */
/******************************************************************************/

/** Headings ******************************************************************/

	h1, h2, h3, h4, h5, h6, dt {
		page-break-after: avoid;
		page-break-inside: avoid;
		font: 100% sans-serif;   /* Reset all font styling to clear out UA styles */
		font-family: inherit;	/* Inherit the font family. */
		line-height: 1.2;		/* Keep wrapped headings compact */
		hyphens: manual;		/* Hyphenated headings look weird */
	}

	h2, h3, h4, h5, h6 {
		margin-top: 3rem;
	}

	h1, h2, h3 {
		color: #005A9C;
		color: var(--heading-text);
	}

	h1 { font-size: 170%; }
	h2 { font-size: 140%; }
	h3 { font-size: 120%; }
	h4 { font-weight: bold; }
	h5 { font-style: italic; }
	h6 { font-variant: small-caps; }
	dt { font-weight: bold; }

/** Subheadings ***************************************************************/

	h1 + h2,
	#profile-and-date {
		/* #profile-and-date is a subtitle in an H2 under the H1 */
		margin-top: 0;
	}
	h2 + h3,
	h3 + h4,
	h4 + h5,
	h5 + h6 {
		margin-top: 1.2em; /* = 1 x line-height */
	}

/** Section divider ***********************************************************/

	:not(.head) > :not(.head) + hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		color: black;
		color: var(--hr-text);
		border: transparent solid 0;
		background: transparent;
	}
	:not(.head) > hr::before {
		content: "\2727\2003\2003\2727\2003\2003\2727";
	}

/******************************************************************************/
/*                            Paragraphs and Lists                            */
/******************************************************************************/

	p {
		margin: 1em 0;
	}

	dd > p:first-child,
	li > p:first-child {
		margin-top: 0;
	}

	ul, ol {
		margin-left: 0;
		padding-left: 2em;
	}

	li {
		margin: 0.25em 0 0.5em;
		padding: 0;
	}

	dl dd {
		margin: 0 0 .5em 2em;
	}

	.head dd + dd { /* compact for header */
		margin-top: -.5em;
	}

	/* Style for algorithms */
	ol.algorithm ol:not(.algorithm),
	.algorithm > ol ol:not(.algorithm) {
	border-left: 0.5em solid #DEF;
	border-left: 0.5em solid var(--algo-border);
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	 padding: .5em;
	 border: thin solid #ddd;
	 border: thin solid var(--algo-border);
	 border-radius: .5em;
	 margin: .5em calc(-0.5em - 1px);
	}
	[data-algorithm]:not(.heading) > :first-child {
	 margin-top: 0;
	}
	[data-algorithm]:not(.heading) > :last-child {
	 margin-bottom: 0;
	}

	/* Style for switch/case <dl>s */
	dl.switch > dd > ol.only,
	dl.switch > dd > .only > ol {
	margin-left: 0;
	}
	dl.switch > dd > ol.algorithm,
	dl.switch > dd > .algorithm > ol {
	margin-left: -2em;
	}
	dl.switch {
	padding-left: 2em;
	}
	dl.switch > dt {
	text-indent: -1.5em;
	margin-top: 1em;
	}
	dl.switch > dt + dt {
	margin-top: 0;
	}
	dl.switch > dt::before {
	content: '\21AA';
	padding: 0 0.5em 0 0;
	display: inline-block;
	width: 1em;
	text-align: right;
	line-height: 0.5em;
	}

/** Terminology Markup ********************************************************/


/******************************************************************************/
/*                                 Inline Markup                              */
/******************************************************************************/

/** Terminology Markup ********************************************************/
	dfn   { /* Defining instance */
		font-weight: bolder;
	}
	a > i { /* Instance of term */
		font-style: normal;
	}
	dt dfn code, code.idl {
		font-size: inherit;
	}
	dfn var {
		font-style: normal;
	}

/** Change Marking ************************************************************/

	del {
		color: #aa0000;
		color: var(--del-text);
		background: transparent;
		background: var(--del-bg);
		text-decoration: line-through;
	}
	ins {
		color: #006100;
		color: var(--ins-text);
		background: transparent;
		background: var(--ins-bg);
		text-decoration: underline;
	}

	/* for amendments (candidate/proposed changes) */

	.amendment ins, .correction ins, .addition ins,
	ins[class^=c] {
		text-decoration-style: dotted;
	}
	.amendment del, .correction del, .addition del,
	del[class^=c] {
		text-decoration-style: dotted;
	}
	.amendment.proposed ins, .correction.proposed ins, .addition.proposed ins,
	ins[class^=c].proposed {
		text-decoration-style: double;
	}
	.amendment.proposed del, .correction.proposed del, .addition.proposed del,
	del[class^=c].proposed {
		text-decoration-style: double;
	}

/** Miscellaneous improvements to inline formatting ***************************/

	sup {
		vertical-align: super;
		font-size: 80%
	}

/******************************************************************************/
/*                                    Code                                    */
/******************************************************************************/

/** General monospace/pre rules ***********************************************/

	pre, code, samp {
		font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
		font-size: .9em;
		hyphens: none;
		text-transform: none;
		text-align: left;
		text-align: start;
		font-variant: normal;
		orphans: 3;
		widows: 3;
		page-break-before: avoid;
	}
	pre code,
	code code {
		font-size: 100%;
	}

	pre {
		margin-top: 1em;
		margin-bottom: 1em;
		overflow: auto;
	}

/** Inline Code fragments *****************************************************/

	/* Do something nice. */

/******************************************************************************/
/*                                    Links                                   */
/******************************************************************************/

/** General Hyperlinks ********************************************************/

	/* We hyperlink a lot, so make it less intrusive */
	a[href] {
		color: #034575;
		color: var(--a-normal-text);
		text-decoration: underline #707070;
		text-decoration: underline var(--a-normal-underline);
		text-decoration-skip-ink: none;
	}
	a:visited {
		color: #034575;
		color: var(--a-visited-text);
		text-decoration-color: #bbb;
		text-decoration-color: var(--a-visited-underline);
	}

	/* Indicate interaction with the link */
	a[href]:focus,
	a[href]:hover {
		text-decoration-thickness: 2px;
	}
	a[href]:active {
		color: #c00;
		color: var(--a-active-text);
		text-decoration-color: #c00;
		text-decoration-color: var(--a-active-underline);
	}

	/* Backout above styling for W3C logo */
	.head .logo,
	.head .logo a {
		border: none;
		text-decoration: none;
		background: transparent;
	}

/******************************************************************************/
/*                                    Images                                  */
/******************************************************************************/

	img {
		border-style: none;
	}

	img, svg {
		/* Intentionally not color-scheme aware. */
		background: white;
	}

	/* For autogen numbers, add
	  .caption::before, figcaption::before { content: "Figure " counter(figure) ". "; }
	*/

	figure, .figure, .sidefigure {
		page-break-inside: avoid;
		text-align: center;
		margin: 2.5em 0;
	}
	.figure img,	.sidefigure img,	figure img,
	.figure object, .sidefigure object, figure object {
		max-width: 100%;
		margin: auto;
		height: auto;
	}
	.figure pre, .sidefigure pre, figure pre {
		text-align: left;
		display: table;
		margin: 1em auto;
	}
	.figure table, figure table {
		margin: auto;
	}
	@media screen and (min-width: 20em) {
		.sidefigure {
			float: right;
			width: 50%;
			margin: 0 0 0.5em 0.5em;
		}
	}
	.caption, figcaption, caption {
		font-style: italic;
		font-size: 90%;
	}
	.caption::before, figcaption::before, figcaption > .marker {
		font-weight: bold;
	}
	.caption, figcaption {
		counter-increment: figure;
	}

	/* DL list is indented 2em, but figure inside it is not */
	dd > .figure, dd > figure { margin-left: -2em; }

/******************************************************************************/
/*                             Colored Boxes                                  */
/******************************************************************************/

	.issue, .note, .example, .assertion, .advisement, blockquote,
	.amendment, .correction, .addition {
		margin: 1em auto;
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	blockquote > :first-child,
	.note  > p:first-child,
	.issue > p:first-child,
	.amendment > p:first-child,
	.correction > p:first-child,
	.addition > p:first-child {
		margin-top: 0;
	}
	blockquote > :last-child,
	.note  > p:last-child,
	.issue > p:last-child,
	.amendment > p:last-child,
	.correction > p:last-child,
	.addition > p:last-child {
		margin-bottom: 0;
	}


	.issue::before, .issue > .marker,
	.example::before, .example > .marker,
	.note::before, .note > .marker,
	details.note > summary > .marker,
	.amendment::before, .amendment > .marker,
	details.amendment > summary > .marker,
	.addition::before, .addition > .marker,
	addition.amendment > summary > .marker,
	.correction::before, .correction > .marker,
	correction.amendment > summary > .marker
	{
		text-transform: uppercase;
		padding-right: 1em;
	}

	.example::before, .example > .marker {
		display: block;
		padding-right: 0em;
	}

/** Blockquotes ***************************************************************/

	blockquote {
		border-color: silver;
		border-color: var(--blockquote-border);
		background: transparent;
		background: var(--blockquote-bg);
		color: currentcolor;
		color: var(--blockquote-text);
	}

/** Open issue ****************************************************************/

	.issue {
		border-color: #e05252;
		border-color: var(--issue-border);
		background: #fbe9e9;
		background: var(--issue-bg);
		color: black;
		color: var(--issue-text);
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		color: #831616;
		color: var(--issueheading-text);
	}
	/* Add .issue::before { content: "Issue " counter(issue) " "; } for autogen numbers,
	  or use class="marker" to mark up the issue number in source. */

/** Example *******************************************************************/

	.example {
		border-color: #e0cb52;
		border-color: var(--example-border);
		background: #fcfaee;
		background: var(--example-bg);
		color: black;
		color: var(--example-text);
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		color: #574b0f;
		color: var(--exampleheading-text);
	}
	/* Add .example::before { content: "Example " counter(example) " "; } for autogen numbers,
	  or use class="marker" to mark up the example number in source. */

/** Non-normative Note ********************************************************/

	.note {
		border-color: #52e052;
		border-color: var(--note-border);
		background: #e9fbe9;
		background: var(--note-bg);
		color: black;
		color: var(--note-text);
		overflow: auto;
	}

	.note::before, .note > .marker,
	details.note > summary {
		color: hsl(120, 70%, 30%);
		color: var(--noteheading-text);
	}
	/* Add .note::before { content: "Note "; } for autogen label,
	  or use class="marker" to mark up the label in source. */

	details.note[open] > summary {
		border-bottom: 1px silver solid;
		border-bottom: 1px var(--notesummary-underline) solid;
	}

/** Assertion Box *************************************************************/
	/*  for assertions in algorithms */

	.assertion {
		border-color: #AAA;
		border-color: var(--assertion-border);
		background: #EEE;
		background: var(--assertion-bg);
		color: black;
		color: var(--assertion-text);
	}

/** Advisement Box ************************************************************/
	/*  for attention-grabbing normative statements */

	.advisement {
		border-color: orange;
		border-color: var(--advisement-border);
		border-style: none solid;
		background: #fec;
		background: var(--advisement-bg);
		color: black;
		color: var(--advisement-text);
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement::before, .advisement > .marker {
		color: #b35f00;
		color: var(--advisementheading-text);
	}

/** Amendment Box *************************************************************/

	.amendment, .correction, .addition {
		border-color: #330099;
		border-color: var(--amendment-border);
		background: #F5F0FF;
		background: var(--amendment-bg);
		color: black;
		color: var(--amendment-text);
	}
	.amendment.proposed, .correction.proposed, .addition.proposed {
		border-style: solid;
		border-block-width: 0.25em;
	}
	.amendment::before, .amendment > .marker,
	details.amendment > summary::before, details.amendment > summary > .marker,
	.correction::before, .correction > .marker,
	details.correction > summary::before, details.correction > summary > .marker,
	.addition::before, .addition > .marker,
	details.addition > summary::before, details.addition > summary > .marker {
		color: #220066;
		color: var(--amendmentheading-text);
	}
	.amendment.proposed::before, .amendment.proposed > .marker,
	details.amendment.proposed > summary::before, details.amendment.proposed > summary > .marker,
	.correction.proposed::before, .correction.proposed > .marker,
	details.correction.proposed > summary::before, details.correction.proposed > summary > .marker,
	.addition.proposed::before, .addition.proposed > .marker,
	details.addition.proposed > summary::before, details.addition.proposed > summary > .marker {
		font-weight: bold;
	}

/** Spec Obsoletion Notice ****************************************************/
	/* obnoxious obsoletion notice for older/abandoned specs. */

	details {
		display: block;
	}
	summary {
		font-weight: bolder;
	}

	.annoying-warning:not(details),
	details.annoying-warning:not([open]) > summary,
	details.annoying-warning[open] {
		background: hsla(40,100%,50%,0.95);
		background: var(--warning-bg);
		color: black;
		color: var(--warning-text);
		padding: .75em 1em;
		border: red;
		border: var(--warning-border);
		border-style: solid none;
		box-shadow: 0 2px 8px black;
		text-align: center;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

@media not print {
	details.annoying-warning[open] {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 2em;
		z-index: 1000;
	}
}

	details.annoying-warning:not([open]) > summary {
		text-align: center;
	}

/** Entity Definition Boxes ***************************************************/

	.def {
		padding: .5em 1em;
		background: #def;
		background: var(--def-bg);
		margin: 1.2em 0;
		border-left: 0.5em solid #8ccbf2;
		border-left: 0.5em solid var(--def-border);
		color: black;
		color: var(--def-text);
	}

/******************************************************************************/
/*                                    Tables                                  */
/******************************************************************************/

	th, td {
		text-align: left;
		text-align: start;
	}

/** Property/Descriptor Definition Tables *************************************/

	table.def {
		/* inherits .def box styling, see above */
		width: 100%;
		border-spacing: 0;
	}

	table.def td,
	table.def th {
		padding: 0.5em;
		vertical-align: baseline;
		border-bottom: 1px solid #bbd7e9;
		border-bottom: 1px solid var(--defrow-border);
	}

	table.def > tbody > tr:last-child th,
	table.def > tbody > tr:last-child td {
		border-bottom: 0;
	}

	table.def th {
		font-style: italic;
		font-weight: normal;
		padding-left: 1em;
		width: 3em;
	}

	/* For when values are extra-complex and need formatting for readability */
	table td.pre {
		white-space: pre-wrap;
	}

	/* A footnote at the bottom of a def table */
	table.def td.footnote {
		padding-top: 0.6em;
	}
	table.def td.footnote::before {
		content: " ";
		display: block;
		height: 0.6em;
		width: 4em;
		border-top: thin solid;
	}

/** Data tables (and properly marked-up index tables) *************************/
	/*
		<table class="data"> highlights structural relationships in a table
		when correct markup is used (e.g. thead/tbody, th vs. td, scope attribute)

		Use class="complex data" for particularly complicated tables --
		(This will draw more lines: busier, but clearer.)

		Use class="long" on table cells with paragraph-like contents
		(This will adjust text alignment accordingly.)
		Alternately use class="longlastcol" on tables, to have the last column assume "long".
	*/

	table {
		word-wrap: normal;
		overflow-wrap: normal;
		hyphens: manual;
	}

	table.data,
	table.index {
		margin: 1em auto;
		border-collapse: collapse;
		border: hidden;
		width: 100%;
	}
	table.data caption,
	table.index caption {
		max-width: 50em;
		margin: 0 auto 1em;
	}

	table.data td,  table.data th,
	table.index td, table.index th {
		padding: 0.5em 1em;
		border-width: 1px;
		border-color: silver;
		border-color: var(--datacell-border);
		border-top-style: solid;
	}

	table.data thead td:empty {
		padding: 0;
		border: 0;
	}

	table.data  thead,
	table.index thead,
	table.data  tbody,
	table.index tbody {
		border-bottom: 2px solid;
	}

	table.data colgroup,
	table.index colgroup {
		border-left: 2px solid;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		border-right: 2px solid;
		border-top: 1px solid silver;
		border-top: 1px solid var(--datacell-border);
		padding-right: 1em;
	}

	table.data th[colspan],
	table.data td[colspan] {
		text-align: center;
	}

	table.complex.data th,
	table.complex.data td {
		border: 1px solid silver;
		border: 1px solid var(--datacell-border);
		text-align: center;
	}

	table.data.longlastcol td:last-child,
	table.data td.long {
		vertical-align: baseline;
		text-align: left;
	}

	table.data img {
		vertical-align: middle;
	}


/*
Alternate table alignment rules

	table.data,
	table.index {
		text-align: center;
	}

	table.data  thead th[scope="row"],
	table.index thead th[scope="row"] {
		text-align: right;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		text-align: right;
	}

Possible extra rowspan handling

	table.data  tbody th[rowspan]:not([rowspan='1']),
	table.index tbody th[rowspan]:not([rowspan='1']),
	table.data  tbody td[rowspan]:not([rowspan='1']),
	table.index tbody td[rowspan]:not([rowspan='1']) {
		border-left: 1px solid silver;
	}

	table.data  tbody th[rowspan]:first-child,
	table.index tbody th[rowspan]:first-child,
	table.data  tbody td[rowspan]:first-child,
	table.index tbody td[rowspan]:first-child{
		border-left: 0;
		border-right: 1px solid silver;
	}
*/

/******************************************************************************/
/*                                  Indices                                   */
/******************************************************************************/


/** Table of Contents *********************************************************/

	.toc a {
		/* More spacing; use padding to make it part of the click target. */
		padding: 0.1rem 1px 0;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Switch to using border-bottom for underlines */
		text-decoration: none;
		border-bottom: 1px solid;
		/* Reverse color scheme */
		color: black;
		color: var(--toclink-text);
		border-color: #3980b5;
		border-color: var(--toclink-underline);
	}
	.toc a:visited {
		color: black;
		color: var(--toclink-visited-text);
		border-color: #054572;
		border-color: var(--toclink-visited-underline);
	}
	.toc a:focus,
	.toc a:hover {
		background: rgba(75%, 75%, 75%, .25);
		background: var(--a-hover-bg);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	.toc a:not(:focus):not(:hover) {
		/* Allow colors to cascade through from link styling */
		border-bottom-color: transparent;
	}

	.toc, .toc ol, .toc ul, .toc li {
		list-style: none; /* Numbers must be inlined into source */
		/* because generated content isn't search/selectable and markers can't do multilevel yet */
		margin:  0;
		padding: 0;
	}
	.toc {
		line-height: 1.1em;
	}

	/* ToC not indented until third level, but font style & margins show hierarchy */
	.toc > li			{ font-weight: bold;   }
	.toc > li li		 { font-weight: normal; }
	.toc > li li li	  { font-size:   95%;	}
	.toc > li li li li	{ font-size:   90%;	}
	.toc > li li li li li { font-size:   85%;	}

	/* @supports not (display:grid) { */
		.toc > li			{ margin: 1.5rem 0;	}
		.toc > li li		 { margin: 0.3rem 0;	}
		.toc > li li li	  { margin-left: 2rem;   }

		/* Section numbers in a column of their own */
		.toc .secno {
			float: left;
			width: 4rem;
			white-space: nowrap;
		}
		.toc > li li li li .secno { font-size: 85%; }
		.toc > li li li li li .secno { font-size: 100%; }

		.toc li {
			clear: both;
		}

		:not(li) > .toc			 { margin-left:  5rem; }
		.toc .secno				 { margin-left: -5rem; }
		.toc > li li li .secno	  { margin-left: -7rem; }
		.toc > li li li li .secno	{ margin-left: -9rem; }
		.toc > li li li li li .secno { margin-left: -11rem; }

		/* Tighten up indentation in narrow ToCs */
		@media (max-width: 30em) {
			:not(li) > .toc			 { margin-left:  4rem; }
			.toc .secno				 { margin-left: -4rem; }
			.toc > li li li			 { margin-left:  1rem; }
			.toc > li li li .secno	  { margin-left: -5rem; }
			.toc > li li li li .secno	{ margin-left: -6rem; }
			.toc > li li li li li .secno { margin-left: -7rem; }
		}
		/* Loosen it on wide screens */
		@media screen and (min-width: 78em) {
			body:not(.toc-inline) :not(li) > .toc			 { margin-left:  4rem; }
			body:not(.toc-inline) .toc .secno				 { margin-left: -4rem; }
			body:not(.toc-inline) .toc > li li li			 { margin-left:  1rem; }
			body:not(.toc-inline) .toc > li li li .secno	  { margin-left: -5rem; }
			body:not(.toc-inline) .toc > li li li li .secno	{ margin-left: -6rem; }
			body:not(.toc-inline) .toc > li li li li li .secno { margin-left: -7rem; }
	}
	/* } */

	@supports (display:grid) and (display:contents) {
		/* Use #toc over .toc to override non-@supports rules. */
		#toc {
			display: grid;
			align-content: start;
			grid-template-columns: auto 1fr;
			grid-column-gap: 1rem;
			column-gap: 1rem;
			grid-row-gap: .6rem;
			row-gap: .6rem;
		}
		#toc h2 {
			grid-column: 1 / -1;
			margin-bottom: 0;
		}
		#toc ol,
		#toc li,
		#toc a {
			display: contents;
			/* Switch <a> to subgrid when supported */
		}
		#toc span {
			margin: 0;
		}
		#toc > .toc > li > a > span {
			/* The spans of the top-level list,
			  comprising the first items of each top-level section. */
			margin-top: 1.1rem;
		}
		#toc#toc .secno { /* Ugh, need more specificity to override base.css */
			grid-column: 1;
			width: auto;
			margin-left: 0;
		}
		#toc .content {
			grid-column: 2;
			width: auto;
			margin-right: 1rem;
			border-bottom: 3px solid transparent;
			margin-bottom: -3px;
		}
		#toc .content:hover,
		#toc .content:focus {
			background: rgba(75%, 75%, 75%, .25);
			background: var(--a-hover-bg);
			border-bottom-color: #054572;
			border-bottom-color: var(--toclink-underline);
		}
		#toc li li li .content {
			margin-left: 1rem;
		}
		#toc li li li li .content {
			margin-left: 2rem;
		}
	}


/** Index *********************************************************************/

	/* Index Lists: Layout */
	ul.index	  { margin-left: 0; columns: 15em; text-indent: 1em hanging; }
	ul.index li	{ margin-left: 0; list-style: none; break-inside: avoid; }
	ul.index li li { margin-left: 1em; }
	ul.index dl	{ margin-top: 0; }
	ul.index dt	{ margin: .2em 0 .2em 20px;}
	ul.index dd	{ margin: .2em 0 .2em 40px;}
	/* Index Lists: Typography */
	ul.index ul,
	ul.index dl { font-size: smaller; }
	@media not print {
		ul.index li a + span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
			color: var(--indexinfo-text);
		}
	}

/** Index Tables *****************************************************/
	/* See also the data table styling section, which this effectively subclasses */

	table.index {
		font-size: small;
		border-collapse: collapse;
		border-spacing: 0;
		text-align: left;
		margin: 1em 0;
	}

	table.index td,
	table.index th {
		padding: 0.4em;
	}

	table.index tr:hover td:not([rowspan]),
	table.index tr:hover th:not([rowspan]) {
		color: black;
		color: var(--indextable-hover-text);
		background: #f7f8f9;
		background: var(--indextable-hover-bg);
	}

	/* The link in the first column in the property table (formerly a TD) */
	table.index th:first-child a {
		font-weight: bold;
	}

/** Outdated warning **********************************************************/

.outdated-spec {
	color: black;
	color: var(--outdatedspec-text);
	background-color: rgba(0,0,0,0.5);
	background-color: var(--outdatedspec-bg);
}

.outdated-warning {
	position: fixed;
	bottom: 50%;
	left: 0;
	right: 0;
	margin: 0 auto;
	width: 50%;
	background: maroon;
	background: var(--outdated-bg);
	color: white;
	color: var(--outdated-text);
	border-radius: 1em;
	box-shadow: 0 0 1em red;
	box-shadow: 0 0 1em var(--outdated-shadow);
	padding: 2em;
	text-align: center;
	z-index: 2;
}

.outdated-warning a {
	color: currentcolor;
	background: transparent;
}

.edited-rec-warning {
	background: darkorange;
	background: var(--editedrec-bg);
	box-shadow: 0 0 1em;
}

.outdated-warning button {
	color: var(--outdated-text);
	border-radius: 1em;
	box-shadow: 0 0 1em red;
	box-shadow: 0 0 1em var(--outdated-shadow);
	padding: 2em;
	text-align: center;
	z-index: 2;
}

.outdated-warning a {
	color: currentcolor;
	background: transparent;
}

.edited-rec-warning {
	background: darkorange;
	background: var(--editedrec-bg);
	box-shadow: 0 0 1em;
}

.outdated-warning button {
	position: absolute;
	top: 0;
	right:0;
	margin: 0;
	border: 0;
	padding: 0.25em 0.5em;
	background: transparent;
	color: white;
	color: var(--outdated-text);
	font:1em sans-serif;
	text-align:center;
}

.outdated-warning span {
	display: block;
}

.outdated-collapsed {
	bottom: 0;
	border-radius: 0;
	width: 100%;
	padding: 0;
}

/******************************************************************************/
/*                                    Print                                   */
/******************************************************************************/

	@media print {
		/* Pages have their own margins. */
		html {
			margin: 0;
		}
		/* Serif for print. */
		body {
			font-family: serif;
		}

		.outdated-warning {
			position: absolute;
			border-style: solid;
			border-color: red;
		}

		.outdated-warning input {
			display: none;
		}
	}
	@page {
		margin: 1.5cm 1.1cm;
	}



/******************************************************************************/
/*                             Overflow Control                               */
/******************************************************************************/

	.figure .caption, .sidefigure .caption, figcaption {
		/* in case figure is overlarge, limit caption to 50em */
		max-width: 50rem;
		margin-left: auto;
		margin-right: auto;
	}
	.overlarge {
		/* Magic to create good item positioning:
		  "content column" is 50ems wide at max; less on smaller screens.
		  Extra space (after ToC + content) is empty on the right.

		  1. When item < content column, centers item in column.
		  2. When content < item < available, left-aligns.
		  3. When item > available, fills available + scroll bar.
		*/
		display: grid;
		grid-template-columns: minmax(0, 50em);
	}
	.overlarge > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-right: calc(13px + 26.5rem - 50vw);
			max-width: none;
		}
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) .overlarge {
			/* 30.5em body padding 50em content area */
			margin-right: calc(40em - 50vw) !important;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) .overlarge {
			/* 4em html margin 30.5em body padding 50em content area */
			margin-right: calc(84.5em - 100vw) !important;
		}
	}

	@media not print {
		.overlarge {
			overflow-x: auto;
			/* See Lea Verou's explanation background-attachment:
			* http://lea.verou.me/2012/04/background-attachment-local/
			*
			background: top left  / 4em 100% linear-gradient(to right,  #ffffff, rgba(255, 255, 255, 0)) local,
						top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local,
						top left  / 1em 100% linear-gradient(to right,  #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						white;
			background-repeat: no-repeat;
			*/
		}
	}
</style>
<style>
    table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
      vertical-align: top;
    }
    th, td {
      border-left: none;
      border-right: none;
      padding: 0px 10px;
    }
    th {
      text-align: center;
    }

    del { background: #fcc; color: #000; text-decoration: line-through; }
    ins { background: #cfc; color: #000; }
    blockquote .highlight:not(.idl) { background: initial; margin: initial; padding: 0.5em }
    blockquote ul { background: inherit; }
    blockquote code.highlight:not(.idl) { padding: initial; }
    blockquote c-[a] { color: inherit; } /* Keyword.Declaration */
    blockquote c-[b] { color: inherit; } /* Keyword.Type */
    blockquote c-[c] { color: inherit; } /* Comment */
    blockquote c-[d] { color: inherit; } /* Comment.Multiline */
    blockquote c-[e] { color: inherit; } /* Name.Attribute */
    blockquote c-[f] { color: inherit; } /* Name.Tag */
    blockquote c-[g] { color: inherit; } /* Name.Variable */
    blockquote c-[k] { color: inherit; } /* Keyword */
    blockquote c-[l] { color: inherit; } /* Literal */
    blockquote c-[m] { color: inherit; } /* Literal.Number */
    blockquote c-[n] { color: inherit; } /* Name */
    blockquote c-[o] { color: inherit; } /* Operator */
    blockquote c-[p] { color: inherit; } /* Punctuation */
    blockquote c-[s] { color: inherit; } /* Literal.String */
    blockquote c-[t] { color: inherit; } /* Literal.String.Single */
    blockquote c-[u] { color: inherit; } /* Literal.String.Double */
    blockquote c-[cp] { color: inherit; } /* Comment.Preproc */
    blockquote c-[c1] { color: inherit; } /* Comment.Single */
    blockquote c-[cs] { color: inherit; } /* Comment.Special */
    blockquote c-[kc] { color: inherit; } /* Keyword.Constant */
    blockquote c-[kn] { color: inherit; } /* Keyword.Namespace */
    blockquote c-[kp] { color: inherit; } /* Keyword.Pseudo */
    blockquote c-[kr] { color: inherit; } /* Keyword.Reserved */
    blockquote c-[ld] { color: inherit; } /* Literal.Date */
    blockquote c-[nc] { color: inherit; } /* Name.Class */
    blockquote c-[no] { color: inherit; } /* Name.Constant */
    blockquote c-[nd] { color: inherit; } /* Name.Decorator */
    blockquote c-[ni] { color: inherit; } /* Name.Entity */
    blockquote c-[ne] { color: inherit; } /* Name.Exception */
    blockquote c-[nf] { color: inherit; } /* Name.Function */
    blockquote c-[nl] { color: inherit; } /* Name.Label */
    blockquote c-[nn] { color: inherit; } /* Name.Namespace */
    blockquote c-[py] { color: inherit; } /* Name.Property */
    blockquote c-[ow] { color: inherit; } /* Operator.Word */
    blockquote c-[mb] { color: inherit; } /* Literal.Number.Bin */
    blockquote c-[mf] { color: inherit; } /* Literal.Number.Float */
    blockquote c-[mh] { color: inherit; } /* Literal.Number.Hex */
    blockquote c-[mi] { color: inherit; } /* Literal.Number.Integer */
    blockquote c-[mo] { color: inherit; } /* Literal.Number.Oct */
    blockquote c-[sb] { color: inherit; } /* Literal.String.Backtick */
    blockquote c-[sc] { color: inherit; } /* Literal.String.Char */
    blockquote c-[sd] { color: inherit; } /* Literal.String.Doc */
    blockquote c-[se] { color: inherit; } /* Literal.String.Escape */
    blockquote c-[sh] { color: inherit; } /* Literal.String.Heredoc */
    blockquote c-[si] { color: inherit; } /* Literal.String.Interpol */
    blockquote c-[sx] { color: inherit; } /* Literal.String.Other */
    blockquote c-[sr] { color: inherit; } /* Literal.String.Regex */
    blockquote c-[ss] { color: inherit; } /* Literal.String.Symbol */
    blockquote c-[vc] { color: inherit; } /* Name.Variable.Class */
    blockquote c-[vg] { color: inherit; } /* Name.Variable.Global */
    blockquote c-[vi] { color: inherit; } /* Name.Variable.Instance */
    blockquote c-[il] { color: inherit; } /* Literal.Number.Integer.Long */
  </style>
  <meta content="Bikeshed version d765c696b, updated Fri Mar 8 15:58:52 2024 -0800" name="generator">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
  <meta content="dark light" name="color-scheme">
<style>
ins  {background-color: #CCFFCC; text-decoration: underline;}
del  {background-color: #FFCACA; text-decoration: line-through;}
table, th, td { border: 1px solid; border-collapse: true; padding: 5px}
p   { hyphens: none }
</style>
<style>/* Boilerplate: style-autolinks */
.css.css, .property.property, .descriptor.descriptor {
    color: var(--a-normal-text);
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

[data-link-type].production::before,
[data-link-type].production::after,
.prod [data-link-type]::before,
.prod [data-link-type]::after {
    content: "";
}

[data-link-type=element],
[data-link-type=element-attr] {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace;
    font-size: .9em;
}
[data-link-type=element]::before { content: "<" }
[data-link-type=element]::after  { content: ">" }

[data-link-type=biblio] {
    white-space: pre;
}

@media (prefers-color-scheme: dark) {
    :root {
        --selflink-text: black;
        --selflink-bg: silver;
        --selflink-hover-text: white;
    }
}
</style>
<style>/* Boilerplate: style-colors */
/* Any --*-text not paired with a --*-bg is assumed to have a transparent bg */
:root {
    color-scheme: light dark;

    --text: black;
    --bg: white;

    --unofficial-watermark: url(https://www.w3.org/StyleSheets/TR/2016/logos/UD-watermark);

    --logo-bg: #1a5e9a;
    --logo-active-bg: #c00;
    --logo-text: white;

    --tocnav-normal-text: #707070;
    --tocnav-normal-bg: var(--bg);
    --tocnav-hover-text: var(--tocnav-normal-text);
    --tocnav-hover-bg: #f8f8f8;
    --tocnav-active-text: #c00;
    --tocnav-active-bg: var(--tocnav-normal-bg);

    --tocsidebar-text: var(--text);
    --tocsidebar-bg: #f7f8f9;
    --tocsidebar-shadow: rgba(0,0,0,.1);
    --tocsidebar-heading-text: hsla(203,20%,40%,.7);

    --toclink-text: var(--text);
    --toclink-underline: #3980b5;
    --toclink-visited-text: var(--toclink-text);
    --toclink-visited-underline: #054572;

    --heading-text: #005a9c;

    --hr-text: var(--text);

    --algo-border: #def;

    --del-text: red;
    --del-bg: transparent;
    --ins-text: #080;
    --ins-bg: transparent;

    --a-normal-text: #034575;
    --a-normal-underline: #bbb;
    --a-visited-text: var(--a-normal-text);
    --a-visited-underline: #707070;
    --a-hover-bg: rgba(75%, 75%, 75%, .25);
    --a-active-text: #c00;
    --a-active-underline: #c00;

    --blockquote-border: silver;
    --blockquote-bg: transparent;
    --blockquote-text: currentcolor;

    --issue-border: #e05252;
    --issue-bg: #fbe9e9;
    --issue-text: var(--text);
    --issueheading-text: #831616;

    --example-border: #e0cb52;
    --example-bg: #fcfaee;
    --example-text: var(--text);
    --exampleheading-text: #574b0f;

    --note-border: #52e052;
    --note-bg: #e9fbe9;
    --note-text: var(--text);
    --noteheading-text: hsl(120, 70%, 30%);
    --notesummary-underline: silver;

    --assertion-border: #aaa;
    --assertion-bg: #eee;
    --assertion-text: black;

    --advisement-border: orange;
    --advisement-bg: #fec;
    --advisement-text: var(--text);
    --advisementheading-text: #b35f00;

    --warning-border: red;
    --warning-bg: hsla(40,100%,50%,0.95);
    --warning-text: var(--text);

    --amendment-border: #330099;
    --amendment-bg: #F5F0FF;
    --amendment-text: var(--text);
    --amendmentheading-text: #220066;

    --def-border: #8ccbf2;
    --def-bg: #def;
    --def-text: var(--text);
    --defrow-border: #bbd7e9;

    --datacell-border: silver;

    --indexinfo-text: #707070;

    --indextable-hover-text: black;
    --indextable-hover-bg: #f7f8f9;

    --outdatedspec-bg: rgba(0, 0, 0, .5);
    --outdatedspec-text: black;
    --outdated-bg: maroon;
    --outdated-text: white;
    --outdated-shadow: red;

    --editedrec-bg: darkorange;
}

@media (prefers-color-scheme: dark) {
    :root {
        --text: #ddd;
        --bg: black;

        --unofficial-watermark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cg fill='%23100808' transform='translate(200 200) rotate(-45) translate(-200 -200)' stroke='%23100808' stroke-width='3'%3E%3Ctext x='50%25' y='220' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EUNOFFICIAL%3C/text%3E%3Ctext x='50%25' y='305' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EDRAFT%3C/text%3E%3C/g%3E%3C/svg%3E");

        --logo-bg: #1a5e9a;
        --logo-active-bg: #c00;
        --logo-text: white;

        --tocnav-normal-text: #999;
        --tocnav-normal-bg: var(--bg);
        --tocnav-hover-text: var(--tocnav-normal-text);
        --tocnav-hover-bg: #080808;
        --tocnav-active-text: #f44;
        --tocnav-active-bg: var(--tocnav-normal-bg);

        --tocsidebar-text: var(--text);
        --tocsidebar-bg: #080808;
        --tocsidebar-shadow: rgba(255,255,255,.1);
        --tocsidebar-heading-text: hsla(203,20%,40%,.7);

        --toclink-text: var(--text);
        --toclink-underline: #6af;
        --toclink-visited-text: var(--toclink-text);
        --toclink-visited-underline: #054572;

        --heading-text: #8af;

        --hr-text: var(--text);

        --algo-border: #456;

        --del-text: #f44;
        --del-bg: transparent;
        --ins-text: #4a4;
        --ins-bg: transparent;

        --a-normal-text: #6af;
        --a-normal-underline: #555;
        --a-visited-text: var(--a-normal-text);
        --a-visited-underline: var(--a-normal-underline);
        --a-hover-bg: rgba(25%, 25%, 25%, .2);
        --a-active-text: #f44;
        --a-active-underline: var(--a-active-text);

        --borderedblock-bg: rgba(255, 255, 255, .05);

        --blockquote-border: silver;
        --blockquote-bg: var(--borderedblock-bg);
        --blockquote-text: currentcolor;

        --issue-border: #e05252;
        --issue-bg: var(--borderedblock-bg);
        --issue-text: var(--text);
        --issueheading-text: hsl(0deg, 70%, 70%);

        --example-border: hsl(50deg, 90%, 60%);
        --example-bg: var(--borderedblock-bg);
        --example-text: var(--text);
        --exampleheading-text: hsl(50deg, 70%, 70%);

        --note-border: hsl(120deg, 100%, 35%);
        --note-bg: var(--borderedblock-bg);
        --note-text: var(--text);
        --noteheading-text: hsl(120, 70%, 70%);
        --notesummary-underline: silver;

        --assertion-border: #444;
        --assertion-bg: var(--borderedblock-bg);
        --assertion-text: var(--text);

        --advisement-border: orange;
        --advisement-bg: #222218;
        --advisement-text: var(--text);
        --advisementheading-text: #f84;

        --warning-border: red;
        --warning-bg: hsla(40,100%,20%,0.95);
        --warning-text: var(--text);

        --amendment-border: #330099;
        --amendment-bg: #080010;
        --amendment-text: var(--text);
        --amendmentheading-text: #cc00ff;

        --def-border: #8ccbf2;
        --def-bg: #080818;
        --def-text: var(--text);
        --defrow-border: #136;

        --datacell-border: silver;

        --indexinfo-text: #aaa;

        --indextable-hover-text: var(--text);
        --indextable-hover-bg: #181818;

        --outdatedspec-bg: rgba(255, 255, 255, .5);
        --outdatedspec-text: black;
        --outdated-bg: maroon;
        --outdated-text: white;
        --outdated-shadow: red;

        --editedrec-bg: darkorange;
    }
    /* In case a transparent-bg image doesn't expect to be on a dark bg,
       which is quite common in practice... */
    img { background: white; }
}
</style>
<style>/* Boilerplate: style-counters */
body {
    counter-reset: example figure issue;
}
.issue {
    counter-increment: issue;
}
.issue:not(.no-marker)::before {
    content: "Issue " counter(issue);
}

.example {
    counter-increment: example;
}
.example:not(.no-marker)::before {
    content: "Example " counter(example);
}
.invalid.example:not(.no-marker)::before,
.illegal.example:not(.no-marker)::before {
    content: "Invalid Example" counter(example);
}

figcaption {
    counter-increment: figure;
}
figcaption:not(.no-marker)::before {
    content: "Figure " counter(figure) " ";
}
</style>
<style>/* Boilerplate: style-issues */
a[href].issue-return {
    float: right;
    float: inline-end;
    color: var(--issueheading-text);
    font-weight: bold;
    text-decoration: none;
}
</style>
<style>/* Boilerplate: style-md-lists */
/* This is a weird hack for me not yet following the commonmark spec
   regarding paragraph and lists. */
[data-md] > :first-child {
    margin-top: 0;
}
[data-md] > :last-child {
    margin-bottom: 0;
}
</style>
<style>/* Boilerplate: style-selflinks */
:root {
    --selflink-text: white;
    --selflink-bg: gray;
    --selflink-hover-text: black;
}
.heading, .issue, .note, .example, li, dt {
    position: relative;
}
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;
}
a.self-link:hover {
    opacity: 1;
}
.heading > a.self-link {
    font-size: 83%;
}
.example > a.self-link,
.note > a.self-link,
.issue > a.self-link {
    /* These blocks are overflow:auto, so positioning outside
       doesn't work. */
    left: auto;
    right: 0;
}
li > a.self-link {
    left: calc(-1 * (3.5rem - 26px) - 2em);
}
dfn > a.self-link {
    top: auto;
    left: auto;
    opacity: 0;
    width: 1.5em;
    height: 1.5em;
    background: var(--selflink-bg);
    color: var(--selflink-text);
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: var(--selflink-hover-text);
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }
</style>
<style>/* Boilerplate: style-syntax-highlighting */
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }

.highlight:not(.idl) { background: rgba(0, 0, 0, .03); }
c-[a] { color: #990055 } /* Keyword.Declaration */
c-[b] { color: #990055 } /* Keyword.Type */
c-[c] { color: #708090 } /* Comment */
c-[d] { color: #708090 } /* Comment.Multiline */
c-[e] { color: #0077aa } /* Name.Attribute */
c-[f] { color: #669900 } /* Name.Tag */
c-[g] { color: #222222 } /* Name.Variable */
c-[k] { color: #990055 } /* Keyword */
c-[l] { color: #000000 } /* Literal */
c-[m] { color: #000000 } /* Literal.Number */
c-[n] { color: #0077aa } /* Name */
c-[o] { color: #999999 } /* Operator */
c-[p] { color: #999999 } /* Punctuation */
c-[s] { color: #a67f59 } /* Literal.String */
c-[t] { color: #a67f59 } /* Literal.String.Single */
c-[u] { color: #a67f59 } /* Literal.String.Double */
c-[cp] { color: #708090 } /* Comment.Preproc */
c-[c1] { color: #708090 } /* Comment.Single */
c-[cs] { color: #708090 } /* Comment.Special */
c-[kc] { color: #990055 } /* Keyword.Constant */
c-[kn] { color: #990055 } /* Keyword.Namespace */
c-[kp] { color: #990055 } /* Keyword.Pseudo */
c-[kr] { color: #990055 } /* Keyword.Reserved */
c-[ld] { color: #000000 } /* Literal.Date */
c-[nc] { color: #0077aa } /* Name.Class */
c-[no] { color: #0077aa } /* Name.Constant */
c-[nd] { color: #0077aa } /* Name.Decorator */
c-[ni] { color: #0077aa } /* Name.Entity */
c-[ne] { color: #0077aa } /* Name.Exception */
c-[nf] { color: #0077aa } /* Name.Function */
c-[nl] { color: #0077aa } /* Name.Label */
c-[nn] { color: #0077aa } /* Name.Namespace */
c-[py] { color: #0077aa } /* Name.Property */
c-[ow] { color: #999999 } /* Operator.Word */
c-[mb] { color: #000000 } /* Literal.Number.Bin */
c-[mf] { color: #000000 } /* Literal.Number.Float */
c-[mh] { color: #000000 } /* Literal.Number.Hex */
c-[mi] { color: #000000 } /* Literal.Number.Integer */
c-[mo] { color: #000000 } /* Literal.Number.Oct */
c-[sb] { color: #a67f59 } /* Literal.String.Backtick */
c-[sc] { color: #a67f59 } /* Literal.String.Char */
c-[sd] { color: #a67f59 } /* Literal.String.Doc */
c-[se] { color: #a67f59 } /* Literal.String.Escape */
c-[sh] { color: #a67f59 } /* Literal.String.Heredoc */
c-[si] { color: #a67f59 } /* Literal.String.Interpol */
c-[sx] { color: #a67f59 } /* Literal.String.Other */
c-[sr] { color: #a67f59 } /* Literal.String.Regex */
c-[ss] { color: #a67f59 } /* Literal.String.Symbol */
c-[vc] { color: #0077aa } /* Name.Variable.Class */
c-[vg] { color: #0077aa } /* Name.Variable.Global */
c-[vi] { color: #0077aa } /* Name.Variable.Instance */
c-[il] { color: #000000 } /* Literal.Number.Integer.Long */

@media (prefers-color-scheme: dark) {
    .highlight:not(.idl) { background: rgba(255, 255, 255, .05); }

    c-[a] { color: #d33682 } /* Keyword.Declaration */
    c-[b] { color: #d33682 } /* Keyword.Type */
    c-[c] { color: #2aa198 } /* Comment */
    c-[d] { color: #2aa198 } /* Comment.Multiline */
    c-[e] { color: #268bd2 } /* Name.Attribute */
    c-[f] { color: #b58900 } /* Name.Tag */
    c-[g] { color: #cb4b16 } /* Name.Variable */
    c-[k] { color: #d33682 } /* Keyword */
    c-[l] { color: #657b83 } /* Literal */
    c-[m] { color: #657b83 } /* Literal.Number */
    c-[n] { color: #268bd2 } /* Name */
    c-[o] { color: #657b83 } /* Operator */
    c-[p] { color: #657b83 } /* Punctuation */
    c-[s] { color: #6c71c4 } /* Literal.String */
    c-[t] { color: #6c71c4 } /* Literal.String.Single */
    c-[u] { color: #6c71c4 } /* Literal.String.Double */
    c-[ch] { color: #2aa198 } /* Comment.Hashbang */
    c-[cp] { color: #2aa198 } /* Comment.Preproc */
    c-[cpf] { color: #2aa198 } /* Comment.PreprocFile */
    c-[c1] { color: #2aa198 } /* Comment.Single */
    c-[cs] { color: #2aa198 } /* Comment.Special */
    c-[kc] { color: #d33682 } /* Keyword.Constant */
    c-[kn] { color: #d33682 } /* Keyword.Namespace */
    c-[kp] { color: #d33682 } /* Keyword.Pseudo */
    c-[kr] { color: #d33682 } /* Keyword.Reserved */
    c-[ld] { color: #657b83 } /* Literal.Date */
    c-[nc] { color: #268bd2 } /* Name.Class */
    c-[no] { color: #268bd2 } /* Name.Constant */
    c-[nd] { color: #268bd2 } /* Name.Decorator */
    c-[ni] { color: #268bd2 } /* Name.Entity */
    c-[ne] { color: #268bd2 } /* Name.Exception */
    c-[nf] { color: #268bd2 } /* Name.Function */
    c-[nl] { color: #268bd2 } /* Name.Label */
    c-[nn] { color: #268bd2 } /* Name.Namespace */
    c-[py] { color: #268bd2 } /* Name.Property */
    c-[ow] { color: #657b83 } /* Operator.Word */
    c-[mb] { color: #657b83 } /* Literal.Number.Bin */
    c-[mf] { color: #657b83 } /* Literal.Number.Float */
    c-[mh] { color: #657b83 } /* Literal.Number.Hex */
    c-[mi] { color: #657b83 } /* Literal.Number.Integer */
    c-[mo] { color: #657b83 } /* Literal.Number.Oct */
    c-[sa] { color: #6c71c4 } /* Literal.String.Affix */
    c-[sb] { color: #6c71c4 } /* Literal.String.Backtick */
    c-[sc] { color: #6c71c4 } /* Literal.String.Char */
    c-[dl] { color: #6c71c4 } /* Literal.String.Delimiter */
    c-[sd] { color: #6c71c4 } /* Literal.String.Doc */
    c-[se] { color: #6c71c4 } /* Literal.String.Escape */
    c-[sh] { color: #6c71c4 } /* Literal.String.Heredoc */
    c-[si] { color: #6c71c4 } /* Literal.String.Interpol */
    c-[sx] { color: #6c71c4 } /* Literal.String.Other */
    c-[sr] { color: #6c71c4 } /* Literal.String.Regex */
    c-[ss] { color: #6c71c4 } /* Literal.String.Symbol */
    c-[fm] { color: #268bd2 } /* Name.Function.Magic */
    c-[vc] { color: #cb4b16 } /* Name.Variable.Class */
    c-[vg] { color: #cb4b16 } /* Name.Variable.Global */
    c-[vi] { color: #cb4b16 } /* Name.Variable.Instance */
    c-[vm] { color: #cb4b16 } /* Name.Variable.Magic */
    c-[il] { color: #657b83 } /* Literal.Number.Integer.Long */
}
</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P3233R0<br>Issues with P2786 ("Trivial Relocatability For C++26")</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Published Proposal, <time class="dt-updated" datetime="2024-04-13">2024-04-13</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt class="editor">Author:
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:giuseppe.dangelo@kdab.com">Giuseppe D'Angelo</a>
     <dt>Audience:
     <dd>EWG, LEWG, SG12
     <dt>Project:
     <dd>ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <div class="p-summary" data-fill-with="abstract">
   <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2>
   <p>This paper highlights some issues with the currently approved design for trivial relocation in the C++ language.</p>
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li><a href="#changelog"><span class="secno">1</span> <span class="content">Changelog</span></a>
    <li>
     <a href="#introduction"><span class="secno">2</span> <span class="content">Introduction</span></a>
     <ol class="toc">
      <li><a href="#what-this-paper-is-not"><span class="secno">2.1</span> <span class="content">What this paper is <strong>not</strong></span></a>
     </ol>
    <li><a href="#why-have-tr-in-the-language-at-all"><span class="secno">3</span> <span class="content">Why have TR in the language at all?</span></a>
    <li><a href="#the-status-quo"><span class="secno">4</span> <span class="content">The status quo</span></a>
    <li><a href="#vectorreallocate"><span class="secno">5</span> <span class="content">What optimizations are possible in the current model?</span></a>
    <li>
     <a href="#missingoptimizations"><span class="secno">6</span> <span class="content">The <strong>missing optimizations</strong></span></a>
     <ol class="toc">
      <li><a href="#troptimizationformoveassignment"><span class="secno">6.1</span> <span class="content">Why are TR optimizations for move assignments not allowed?</span></a>
      <li><a href="#does-anyone-even-use-this-specific-optimization-for-move-assignments"><span class="secno">6.2</span> <span class="content">Does anyone even use this specific optimization for move assignments?</span></a>
      <li><a href="#optimizing-swaps"><span class="secno">6.3</span> <span class="content">Optimizing swaps</span></a>
      <li><a href="#can-we-just-reformulate-vectorinsert-erase-etc-not-to-do-assignments-but-constructions-destructions"><span class="secno">6.4</span> <span class="content">Can we "just" reformulate <code class="highlight"><c- n>vector</c-><c- o>::</c-><c- n>insert</c-></code> / <code class="highlight"><c- n>erase</c-></code> / etc. not to do assignments but constructions/destructions?</span></a>
      <li><a href="#instead-of-adding-another-language-facility-for-this-optimization-can-we-use-reflection-instead"><span class="secno">6.5</span> <span class="content">Instead of adding another language facility for this optimization, can we use reflection instead?</span></a>
      <li><a href="#can-the-current-model-of-tr-be-extended-to-cover-the-move-assignment-optimizations-in-the-language-at-a-later-stage"><span class="secno">6.6</span> <span class="content">Can the current model of TR be extended to cover the move-assignment optimizations, in the language, <em>at a later stage</em>?</span></a>
     </ol>
    <li>
     <a href="#lack-of-library-api"><span class="secno">7</span> <span class="content">Lack of library API</span></a>
     <ol class="toc">
      <li><a href="#do-we-know-we-got-the-design-right"><span class="secno">7.1</span> <span class="content">Do we know we got the design right?</span></a>
      <li><a href="#libqoi"><span class="secno">7.2</span> <span class="content">Leaving the TR status of Standard Library datatypes as QoI</span></a>
     </ol>
    <li>
     <a href="#what-even-is-relocation"><span class="secno">8</span> <span class="content">What even <strong>is</strong> relocation?</span></a>
     <ol class="toc">
      <li><a href="#is-tr-its-own-primitive-operation-on-a-type"><span class="secno">8.1</span> <span class="content">Is TR its own primitive operation on a type?</span></a>
      <li><a href="#why-allowing-for-trivially-copyable-types-that-arent-tr"><span class="secno">8.2</span> <span class="content">Why allowing for trivially copyable types that aren’t TR?</span></a>
      <li><a href="#polymorphic"><span class="secno">8.3</span> <span class="content">Unclear behaviors for polymorphic classes</span></a>
     </ol>
    <li>
     <a href="#enforcementmodel"><span class="secno">9</span> <span class="content">Enforcement model</span></a>
     <ol class="toc">
      <li><a href="#what-is-the-cost-benefit-ratio-of-enforcement"><span class="secno">9.1</span> <span class="content">What is the cost/benefit ratio of enforcement?</span></a>
      <li><a href="#automatic-tr-is-still-not-entirely-safe"><span class="secno">9.2</span> <span class="content">Automatic TR is still not entirely safe</span></a>
     </ol>
    <li>
     <a href="#p1144s-trivial-relocation-model"><span class="secno">10</span> <span class="content">P1144’s trivial relocation model</span></a>
     <ol class="toc">
      <li><a href="#overall-differences-between-p2786-and-p1144"><span class="secno">10.1</span> <span class="content">Overall differences between P2786 and P1144</span></a>
      <li>
       <a href="#p1144s-tr-semantics"><span class="secno">10.2</span> <span class="content">P1144’s TR semantics</span></a>
       <ol class="toc">
        <li><a href="#trivially-copyable-always-implies-automatically-trivially-relocatable"><span class="secno">10.2.1</span> <span class="content">Trivially copyable always implies automatically trivially relocatable</span></a>
        <li><a href="#tr-is-an-intrinsic-quality"><span class="secno">10.2.2</span> <span class="content">TR is an intrinsic quality</span></a>
        <li><a href="#trivially-copyable-types-are-a-subset-of-trivially-relocatable"><span class="secno">10.2.3</span> <span class="content">Trivially copyable types are a subset of trivially relocatable</span></a>
       </ol>
      <li><a href="#which-optimizations-are-possible-in-p1144s-model"><span class="secno">10.3</span> <span class="content">Which optimizations are possible in P1144’s model?</span></a>
      <li><a href="#which-optimizations-are-not-possible-in-p1144s-model"><span class="secno">10.4</span> <span class="content">Which optimizations are <strong>not possible</strong> in P1144’s model?</span></a>
     </ol>
    <li><a href="#summary"><span class="secno">11</span> <span class="content">Summary</span></a>
    <li>
     <a href="#a-possible-way-forward"><span class="secno">12</span> <span class="content">A possible way forward</span></a>
     <ol class="toc">
      <li><a href="#disclaimer"><span class="secno">12.1</span> <span class="content">Disclaimer</span></a>
      <li><a href="#proposed-action-points"><span class="secno">12.2</span> <span class="content">Proposed action points</span></a>
     </ol>
    <li><a href="#acknowledgements"><span class="secno">13</span> <span class="content">Acknowledgements</span></a>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="changelog"><span class="secno">1. </span><span class="content">Changelog</span><a class="self-link" href="#changelog"></a></h2>
   <ul>
    <li data-md>
     <p>R0</p>
     <ul>
      <li data-md>
       <p>First submission</p>
     </ul>
   </ul>
   <h2 class="heading settled" data-level="2" id="introduction"><span class="secno">2. </span><span class="content">Introduction</span><a class="self-link" href="#introduction"></a></h2>
   <p>In the Tokyo 2024 meeting <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> ("Trivial Relocatability For
C++26") was adopted by EWG. <strong>We believe that the design for trivial
relocation of that paper is too restrictive</strong>, and blocks a significant
amount of optimizations. Not only this means that the Standard Library
won’t get as many benefits as it could, but also third-party libraries
(such as Qt, Folly, BSL, etc.) that define their own trivial relocation
model may not be able to fully adopt the Standard’s.</p>
   <p><b>We also fear that the "vocabulary" for trivial relocation
standardized by <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> risks limiting future extensions</b>.</p>
   <p>On the other hand, <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a> ("std::is_trivially_relocatable")'s
design for trivial relocation allows for some <strong>different</strong> optimizations. These optimizations more closely match existing
practices, but do not necessarily include the ones that <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> allows for.</p>
   <p>In other words: <strong>there is a split between the two proposals w.r.t.
what can be effectively optimized</strong> (and how). We believe that this is
a subtle but very important difference that the "comparison paper" <a data-link-type="biblio" href="#biblio-p2814r0" title="Trivial Relocatability --- Comparing P1144 with P2786">[P2814R0]</a> might not have emphasized enough; this aspect got possibly
entangled with the long listing of minutiae about syntactic differences.</p>
   <p>Instead, we believe that a design that satisfies both <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> and <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a> can and should be found.</p>
   <div class="note" role="note">
    <p><em>Editorial note</em>: in the rest of this paper, for the sake of brevity,
we are going to use "TR" instead of "trivial relocation" / "trivially
relocatable" / "trivial relocatability" and similar. We hope that this
will not cause any confusion for the reader.</p>
   </div>
   <h3 class="heading settled" data-level="2.1" id="what-this-paper-is-not"><span class="secno">2.1. </span><span class="content">What this paper is <strong>not</strong></span><a class="self-link" href="#what-this-paper-is-not"></a></h3>
   <p>This paper tries to focus on some high-level issues with the two
competing proposals for trivial relocation in C++. We will deliberately
try to avoid any discussions regarding the low-level mechanics, such as
"should TR be expressed via a keyword or via an attribute", "what is
precisely the API to (trivially) relocate an object", "should we have a
type trait or a concept" and so on. While these practical aspects are
important, we fear that these discussions risk distracting from the
broader picture.</p>
   <p>This paper is not a blanket endorsement of <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a>'s trivial
relocation design, as that one also has some possible shortcomings that
may leave some users unsatisfied (which is likely why <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> was
introduced). However, if we were to choose only one between the two
proposals as they exist today, we would prefer <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a>.</p>
   <p>Finally, this paper is also not an "oven-ready counter-proposal" to
either <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> or <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a>. We do not have a complete solution
for many of the problems that we are going to highlight, only ideas
and sketches for a way forward.</p>
   <h2 class="heading settled" data-level="3" id="why-have-tr-in-the-language-at-all"><span class="secno">3. </span><span class="content">Why have TR in the language at all?</span><a class="self-link" href="#why-have-tr-in-the-language-at-all"></a></h2>
   <p>The main driver behind the TR proposals (and the existing usage of TR
in third-party libraries) is to unlock a family of optimization
techniques. These techniques have a common theme: turn certain
combinations of move operations and/or destruction operations into byte
manipulations. These manipulations are already available for types
that are trivially copyable, but are not allowed for many other useful
types (such as <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>).</p>
   <p>The main reasons behind adding a proper definition of TR to the
language are:</p>
   <ol>
    <li data-md>
     <p><strong>to precisely define what are the characteristics of a type so that
it’s eligible for TR</strong> (that is, it can be manipulated at the byte
level instead of requiring calls to move operations, destructors,
etc.);</p>
    <li data-md>
     <p><strong>to give proper names and semantics to these byte level
operations</strong>, especially concerning the lifetime of the objects
involved. Without support in the language, existing libraries that
use these TR optimizations always tread on <em>"Undefined Behavior That
Works In Practice"</em>.</p>
     <div class="note" role="note"> Indeed, this kind of low-level object manipulations is an area that
(historically) has always been full of such UBTWIP. Thankfully,
more and more facilities are being added to reduce this source of
UB. In this sense, language support for TR is an important step in
this direction, and we strongly welcome it. </div>
    <li data-md>
     <p><strong>to allow type properties to naturally propagate and compose when
defining new types</strong>.
This is completely in line with how other type properties already
work and propagate: copyability, trivial copyability, and so on.</p>
     <p>For instance, "Rule Of Zero" types should automatically be TR if
their subobjects can be TR; this automatic propagation is
only possible via a language mechanism, not via a library one
(especially lacking reflection):</p>
<pre class="highlight"><c- c1>// Given this:</c->
<c- k>class</c-> <c- nc>A</c-> <c- n>TRIVIALLY_RELOCATABLE_TAG</c-> <c- p>{</c-> <c- o>~~~</c-> <c- p>};</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>A</c-><c- o>></c-><c- p>);</c->

<c- c1>// We want this to hold automatically:</c->
<c- k>class</c-> <c- nc>B</c-> <c- p>{</c-> <c- n>A</c-> <c- n>a</c-><c- p>;</c-> <c- p>};</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>B</c-><c- o>></c-><c- p>);</c->
</pre>
   </ol>
   <h2 class="heading settled" data-level="4" id="the-status-quo"><span class="secno">4. </span><span class="content">The status quo</span><a class="self-link" href="#the-status-quo"></a></h2>
   <p>The following is a summary of the currently approved language design
for TR in <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a>.</p>
   <ul>
    <li data-md>
     <p>C++26 types will have a new property/category called
"trivially relocatable", comprising scalars, TR classes, arrays
of TR types and cv-qualified versions of TR types.</p>
    <li data-md>
     <p>A class can be manually marked as TR (or not) by using a new
contextual keyword (<code class="highlight"><c- n>trivially_relocatable</c-></code>, with an optional
boolean argument to be able to express conditional TR).</p>
    <li data-md>
     <p>In alternative, an <em>unmarked</em> class is automatically TR if:</p>
     <ul>
      <li data-md>
       <p>all of its subobjects are of TR type or of reference type; and</p>
      <li data-md>
       <p>it has no virtual bases; and</p>
      <li data-md>
       <p>it has a non-deleted non-user-provided destructor; and</p>
      <li data-md>
       <p>it is move constructible via a non-deleted non-user-provided constructor.</p>
     </ul>
    <li data-md>
     <p>In case a class is manually marked as TR and has either a non-TR
subobject or a virtual base, then the program is ill-formed. In
other words, the language actively checks that a type marked as
TR also supports TR for all of its subobjects.</p>
   </ul>
   <h2 class="heading settled" data-level="5" id="vectorreallocate"><span class="secno">5. </span><span class="content">What optimizations are possible in the current model?</span><a class="self-link" href="#vectorreallocate"></a></h2>
   <p>Given an object <code class="highlight"><c- n>A</c-></code> of a TR type <code class="highlight"><c- n>T</c-></code>, one may turn the sequence of
these two operations:</p>
   <ol>
    <li data-md>
     <p>move construction of an existing object <code class="highlight"><c- n>A</c-></code> into a new object <code class="highlight"><c- n>B</c-></code>;</p>
    <li data-md>
     <p>followed by the destruction of <code class="highlight"><c- n>A</c-></code>;</p>
   </ol>
   <p>into a mere byte copy (e.g. <code class="highlight"><c- n>memcpy</c-></code> or <code class="highlight"><c- n>memmove</c-></code>) from the storage of <code class="highlight"><c- n>A</c-></code> into the storage where to build <code class="highlight"><c- n>B</c-></code>. In particular, <em>no calls to
the move constructor or to the destructor take place</em>. The storage for <code class="highlight"><c- n>A</c-></code> can then be reused or freed.</p>
   <p>Due to the aforementioned lifetime concerns, code that wants to use
this optimization can’t <em>literally</em> apply <code class="highlight"><c- n>memcpy</c-></code> without running into
UB, because a TR type is not necessarily trivially copyable. Instead, a
new facility is provided in order to perform TR, with the idea that the
facility performs (the equivalent of) a <code class="highlight"><c- n>memcpy</c-></code>, as well as correctly
starts and ends the lifetimes in the abstract machine for the involved
objects.</p>
   <div class="note" role="note">
    <p>The exact shape of the facility (keyword, library function, ...)
is not relevant for the purpose of the present paper.</p>
   </div>
   <p>In pseudocode:</p>
<pre class="highlight"><c- c1>// Given:</c->
<c- n>T</c-> <c- o>*</c-><c- n>ptrA</c-> <c- o>=</c-> <c- o>~~~</c-><c- p>;</c->        <c- c1>// alive</c->
<c- n>T</c-> <c- o>*</c-><c- n>storageForB</c-> <c- o>=</c-> <c- o>~~~</c-><c- p>;</c-> <c- c1>// uninitialized</c->

<c- c1>// Without trivial relocation:</c->
<c- k>new</c-> <c- p>(</c-><c- n>storageForB</c-><c- p>)</c-> <c- n>T</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- o>*</c-><c- n>ptrA</c-><c- p>));</c->
<c- n>ptrA</c-><c- o>->~</c-><c- n>T</c-><c- p>();</c->

<c- c1>// With trivial relocation: call a facility that performs the equivalent of</c->
<c- n>std</c-><c- o>::</c-><c- n>memcpy</c-><c- p>(</c-><c- n>storageForB</c-><c- p>,</c-> <c- n>ptrA</c-><c- p>,</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>));</c->
<c- n>end_lifetime</c-><c- p>(</c-><c- n>ptrA</c-><c- p>);</c->
<c- n>start_lifetime</c-><c- p>(</c-><c- n>storageForB</c-><c- p>);</c->
</pre>
   <p>The "textbook example" of a non-trivially copyable type that has
suitable characteristics for this kind of optimization is <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-></code>.</p>
   <p>If we apply this logic in bulk, to multiple contiguous objects, the
byte operations can be coalesced into one big <code class="highlight"><c- n>memcpy</c-></code>/<code class="highlight"><c- n>memmove</c-></code> call.
This has a significant performance benefit in terms of execution speed,
as well as interesting secondary effects (fewer template
instantiations, reducing build times and code bloat); both <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> and <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a> provide benchmarks.</p>
   <p>The "textbook example" where this optimization is usable is during the
reallocation of a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-></code>, where objects are move-constructed
from the old storage into some newly allocated storage, and then the
old objects are destroyed and the old storage is released.</p>
   <div class="note" role="note">
    <p>This allows to reallocate a vector-like container by simply calling <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>realloc</c-></code> for a further performance benefit. <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-></code>, being
allocator-aware, cannot use <code class="highlight"><c- n>realloc</c-></code> yet because such an API is
missing from allocators.</p>
   </div>
   <hr>
   <p>It’s important to underline that the current requirements for TR types
are meant to support this optimization model. In particular:</p>
   <ul>
    <li data-md>
     <p>a type isn’t automatically TR if it has user-defined move
constructors or destructors. If we cannot reason about what those
operations do, we cannot claim in general that they’re
equivalent to a <code class="highlight"><c- n>memcpy</c-></code>;</p>
    <li data-md>
     <p>we must exclude classes with virtual bases, because virtual
bases may be implemented via self-referential pointers (that is,
pointers that point into the object itself), which therefore makes
objects of these classes not relocatable via a mere <code class="highlight"><c- n>memcpy</c-></code> (the
pointers need to be adjusted);</p>
     <ul>
      <li data-md>
       <p>on the other hand, classes with virtual functions can be TR in
the current model, because the virtual pointers just point to a
static piece of information (the virtual table of the type)
which is stored <em>outside</em> of the object itself (on all common
ABIs);</p>
     </ul>
    <li data-md>
     <p>the <strong>presence of assignment operators</strong> is not considered at all,
because in this model we don’t optimize assignments, only
move-construction and destruction.</p>
   </ul>
   <h2 class="heading settled" data-level="6" id="missingoptimizations"><span class="secno">6. </span><span class="content">The <strong>missing optimizations</strong></span><a class="self-link" href="#missingoptimizations"></a></h2>
   <p>There is another TR-related optimization which is not automatically
allowed by the currently model: <b>using TR in order to optimize move <em>assignments</em> as well as move constructions / destructions.</b></p>
   <p>Consider for instance a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- n>X</c-><c- o>></c-></code> which is not at full capacity.</p>
   <p>An insertion in the middle of the vector requires "shifting" all the
elements at and after the insertion position (the "tail"), in order to
make room for the new element to insert. This is realized via a move
construction (the last element of the vector gets move-constructed into
the uninitialized storage, into the vector’s extra capacity), followed
by a series of move assignments for the rest of the tail of the vector.</p>
   <p>Finally, we can copy or move-assign the element to insert into its
final position.</p>
   <p>If <code class="highlight"><c- n>X</c-></code> satisfies certain type requirements, instead of doing this
sequence of a move construction and assignments, we could just <code class="highlight"><c- n>memmove</c-></code> the contents of the vector by one position "to the right" in
order to make room for the new element.</p>
   <p>In pseudocode:</p>
<pre class="highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
<c- n>vector</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>insert</c-><c- p>(</c-><c- b>size_t</c-> <c- n>position</c-><c- p>,</c-> <c- n>T</c-> <c- o>&amp;&amp;</c-><c- n>t</c-><c- p>)</c->
<c- p>{</c->
    <c- c1>// ... separately deal with "full capacity" ...</c->
    <c- c1>// ... separately deal with append at the end ...</c->

    <c- n>assert</c-><c- p>(</c-><c- n>m_size</c-> <c- o>&lt;</c-> <c- n>m_capacity</c-><c- p>);</c->

    <c- k>if</c-> <c- k>constexpr</c-> <c- p>(</c-> <c- d>/* does T support this optimization? */</c-> <c- p>)</c-> <c- p>{</c->
        <c- c1>// bytewise move the tail one position forward, to create room</c->
        <c- n>std</c-><c- o>::</c-><c- n>memmove</c-><c- p>(</c-><c- n>m_begin</c-> <c- o>+</c-> <c- n>position</c-> <c- o>+</c-> <c- mi>1</c-><c- p>,</c->
                     <c- n>m_begin</c-> <c- o>+</c-> <c- n>position</c-><c- p>,</c->
                     <c- p>(</c-><c- n>m_size</c-> <c- o>-</c-> <c- n>position</c-><c- p>)</c-> <c- o>*</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>));</c->
        <c- c1>// move construct the element to be inserted in the "window" so created</c->
        <c- k>new</c-> <c- p>(</c-><c- n>m_begin</c-> <c- o>+</c-> <c- n>position</c-><c- p>)</c-> <c- n>T</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>t</c-><c- p>));</c->
    <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
        <c- c1>// move construct in the extra capacity</c->
        <c- k>new</c-> <c- p>(</c-><c- n>m_begin</c-> <c- o>+</c-> <c- n>m_size</c-><c- p>)</c-> <c- n>T</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>m_begin</c-><c- p>[</c-><c- n>m_size</c-> <c- o>-</c-> <c- mi>1</c-><c- p>]));</c->
        <c- c1>// move assign the tail one position forward</c->
        <c- n>std</c-><c- o>::</c-><c- n>move_backward</c-><c- p>(</c-><c- n>m_begin</c-> <c- o>+</c-> <c- n>position</c-><c- p>,</c->
                           <c- n>m_begin</c-> <c- o>+</c-> <c- n>m_size</c-> <c- o>-</c-> <c- mi>1</c-><c- p>,</c->
                           <c- n>m_begin</c-> <c- o>+</c-> <c- n>m_size</c-><c- p>);</c->
        <c- c1>// move assign the element to be inserted in the moved-from "window"</c->
        <c- n>m_begin</c-><c- p>[</c-><c- n>position</c-><c- p>]</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>t</c-><c- p>);</c->
    <c- p>}</c->

    <c- c1>// update bookkeeping</c->
<c- p>}</c->
</pre>
   <p>The same kind of reasoning can be applied for <em>erasing</em> an element in the
middle of a vector. Normally, erasing involves a number of
move-assignments "to the left", overwriting the element that needs to
be destroyed, and then destroying the moved-from last element of the
vector.</p>
   <p>Again, given a suitable type <code class="highlight"><c- n>X</c-></code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- n>X</c-><c- o>>::</c-><c- n>erase</c-></code> could instead
use this strategy:</p>
   <ul>
    <li data-md>
     <p>destroy the element;</p>
    <li data-md>
     <p><code class="highlight"><c- n>memmove</c-></code> the tail one position to the left.</p>
   </ul>
   <hr>
   <p>These optimizations for insert/erase can and are employed <em>today</em>, for
instance, if <code class="highlight"><c- n>X</c-></code> is a trivially copyable type. Once more <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> is the textbook example of a non-trivially copyable
type for which these optimizations are in principle possible.</p>
   <h3 class="heading settled" data-level="6.1" id="troptimizationformoveassignment"><span class="secno">6.1. </span><span class="content">Why are TR optimizations for move assignments not allowed?</span><a class="self-link" href="#troptimizationformoveassignment"></a></h3>
   <p>In the currently adopted model (<a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a>) one can have types that
are TR, yet have user-defined assignment operators. Consider a type
with reference semantics like:</p>
<pre class="highlight"><c- k>struct</c-> <c- nc>IRef</c-> <c- p>{</c->
    <c- b>int</c-> <c- o>&amp;</c-><c- n>ref</c-><c- p>;</c->
    <c- n>IRef</c-> <c- o>&amp;</c-><c- k>operator</c-><c- o>=</c-><c- p>(</c-><c- k>const</c-> <c- n>IRef</c-> <c- o>&amp;</c-><c- n>other</c-><c- p>)</c-> <c- p>{</c-> <c- n>ref</c-> <c- o>=</c-> <c- n>other</c-><c- p>.</c-><c- n>ref</c-><c- p>;</c-> <c- k>return</c-> <c- o>*</c-><c- k>this</c-><c- p>;</c-> <c- p>}</c->
<c- p>};</c->
</pre>
   <p><strong>This type is automatically trivially relocatable</strong> in the currently
adopted model. It has:</p>
   <ul>
    <li data-md>
     <p>no non-TR subobjects;</p>
    <li data-md>
     <p>no virtual base classes;</p>
    <li data-md>
     <p>no user-defined or deleted move constructors or destructors,</p>
   </ul>
   <p>and therefore it satisfies all the criteria for being implicitly TR.</p>
   <p>This is OK, in the sense that it is perfectly fine to use <code class="highlight"><c- n>memcpy</c-></code> in
order to reallocate a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- n>IRef</c-><c- o>></c-></code> (TR instead of move
construction + destruction, as discussed above).</p>
   <p>This means that an operation such as erasing an element from such a
vector <strong>must</strong> be implemented via a series of move-assignments and a
destruction, because one can see the side-effects of such assignments. <b>Turning the <em>assignments</em> into manipulation of bytes is not allowed
for something like <code class="highlight"><c- n>IRef</c-></code></b>.</p>
   <p>Examples of types with <code class="highlight"><c- n>IRef</c-></code> semantics are for instance <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- b>int</c-> <c- o>&amp;></c-></code>, or <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>pmr</c-></code> types like <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>pmr</c-><c- o>::</c-><c- n>string</c-></code>.</p>
   <hr>
   <p>The conclusion is that <b>the currently adopted model for TR does not
distinguish between <code class="highlight"><c- n>IRef</c-></code> (TR for move construction only) and
something like <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> (TR for move construction and move
assignment)</b>.</p>
   <p>Ultimately, it boils down to the fact that there are types for which
move assignment is "equivalent" to destruction+move construction, and
types for which this isn’t, and the current TR model does not
distinguish between the two.</p>
   <div class="note" role="note">
    <p>This last remark is important, because it underlines the fact that the
optimization for move assignements is a generalization of the currently
adopted TR model. If a move assignment for a TR type <code class="highlight"><c- n>T</c-></code> is equivalent
to destruction of the target and move construction from the source, it
also means that we can turn this sequence:</p>
<pre class="highlight"><c- n>T</c-> <c- o>*</c-><c- n>target</c-> <c- o>=</c-> <c- o>~~~</c-><c- p>;</c-> <c- c1>// alive</c->
<c- n>T</c-> <c- o>*</c-><c- n>source</c-> <c- o>=</c-> <c- o>~~~</c-><c- p>;</c-> <c- c1>// alive</c->

<c- o>*</c-><c- n>target</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- o>*</c-><c- n>source</c-><c- p>);</c->
<c- n>source</c-><c- o>->~</c-><c- n>T</c-><c- p>();</c->
</pre>
    <p>into</p>
<pre class="highlight"><c- n>target</c-><c- o>->~</c-><c- n>T</c-><c- p>();</c->
<c- n>trivially_relocate</c-><c- p>(</c-><c- n>source</c-><c- p>,</c-> <c- n>target</c-><c- p>);</c-> <c- c1>// as per the currently adopted model</c->
</pre>
    <p>which is what we want to exploit for instance in <code class="highlight"><c- n>vector</c-><c- o>::</c-><c- n>erase</c-></code>.</p>
   </div>
   <p>Since there is no distinction in the language (<code class="highlight"><c- n>IRef</c-></code> and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-></code> are both TR and non-trivially move assignable),
it follows that <strong>in the currently adopted model we cannot apply any TR
optimization for move assignments</strong>; <code class="highlight"><c- n>erase</c-></code> and <code class="highlight"><c- n>insert</c-></code> into vectors <em>cannot</em> be optimized as shown earlier.</p>
   <div class="note" role="note">
    <p>It is important to note that <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a>'s TR model we would instead
have optimization, because that model checks for the presence of
user-defined assignment operators. We will discuss this later in the
paper.</p>
   </div>
   <h3 class="heading settled" data-level="6.2" id="does-anyone-even-use-this-specific-optimization-for-move-assignments"><span class="secno">6.2. </span><span class="content">Does anyone even use this specific optimization for move assignments?</span><a class="self-link" href="#does-anyone-even-use-this-specific-optimization-for-move-assignments"></a></h3>
   <p><strong>Many third party libraries (Qt, Folly, Abseil, BSL) do use it</strong>; <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a> has a thorough survey in §2.1.</p>
   <p>The reason for the "popularity" of this optimization for move
assignments is that it is in principle available for a <em>huge</em> number of
vocabulary types: <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-></code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-></code>, most container
types, string types (but not necessarily <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>string</c-></code>, which may not
be TR at all), <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>optional</c-></code> and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>variant</c-></code> (depending on
the types they hold), and so on.</p>
   <p>Custom allocators/deleters of course play a role in this, in the sense
that they may do have reference semantics; but we believe that it is
unfair to "globally" impede this optimization for everyone. It should
just get forbidden for such specific deleters or allocators.</p>
   <p>In conclusion, it is our opinion that <strong>it is extremely suboptimal to
miss this optimization opportunity</strong>, given the widespread precedent
for it.</p>
   <h3 class="heading settled" data-level="6.3" id="optimizing-swaps"><span class="secno">6.3. </span><span class="content">Optimizing swaps</span><a class="self-link" href="#optimizing-swaps"></a></h3>
   <p><b>Allowing the optimization of move assignments is also a key building
block into making trivially swappable types</b>; and, consequently, <strong>optimize swap-based algorithms via TR</strong>. All these optimization
opportunities are unavailable in the currently adopted model.</p>
   <h3 class="heading settled" data-level="6.4" id="can-we-just-reformulate-vectorinsert-erase-etc-not-to-do-assignments-but-constructions-destructions"><span class="secno">6.4. </span><span class="content">Can we "just" reformulate <code class="highlight"><c- n>vector</c-><c- o>::</c-><c- n>insert</c-></code> / <code class="highlight"><c- n>erase</c-></code> / etc. not to do assignments but constructions/destructions?</span><a class="self-link" href="#can-we-just-reformulate-vectorinsert-erase-etc-not-to-do-assignments-but-constructions-destructions"></a></h3>
   <p>While certainly possible in terms of abstract design, such a change
would constitute an API break: several of those operations either
specify to use assignments, or they de-facto do them today and a
change would break existing code (Hyrum’s law).</p>
   <p>Given the longevity of these APIs and their centrality, we therefore do
not believe that such a break would be even remotely acceptable.</p>
   <p><a data-link-type="biblio" href="#biblio-p2959r0" title="Container Relocation">[P2959R0]</a> ("Container Relocation") discusses a library-based approach
to allow TR for move assignments. The key building block is a new type
trait (called <code class="highlight"><c- n>container_replace_with_assignment</c-></code> in the paper). By
default, this trait would keep the existing semantics (use move
assignments); however, types will be able to opt into the trait, and
therefore enable <code class="highlight"><c- n>erase</c-></code>, <code class="highlight"><c- n>insert</c-></code> and similar operations to use TR.</p>
   <p><strong>We strongly reject a library-based approach for this use case.</strong></p>
   <p>As we discussed in the introduction, a <em>language</em> approach is necessary
for this property to naturally propagate and compose:</p>
<pre class="highlight"><c- c1>// Given:</c->
<c- k>struct</c-> <c- nc>A</c-> <c- p>{</c-> <c- o>~~~</c-> <c- p>};</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>A</c-><c- o>></c-><c- p>);</c->

<c- c1>// Mark the type</c->
<c- k>template</c-> <c- o>&lt;></c->
<c- kr>inline</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>std</c-><c- o>::</c-><c- n>container_replace_with_assignment</c-><c- o>&lt;</c-><c- n>A</c-><c- o>></c-> <c- o>=</c-> false<c- p>;</c->


<c- c1>// Then:</c->
<c- k>struct</c-> <c- nc>B</c-> <c- p>{</c-> <c- n>A</c-> <c- n>a</c-><c- p>;</c-> <c- p>};</c->

<c- c1>// Automatically true, because of language rules:</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>B</c-><c- o>></c-><c- p>);</c->

<c- c1>// FAIL! A library trait isn't propagated.</c->
<c- k>static_assert</c-><c- p>(</c-><c- o>!</c-><c- n>std</c-><c- o>::</c-><c- n>container_replace_with_assignment</c-><c- o>&lt;</c-><c- n>B</c-><c- o>></c-><c- p>);</c->
</pre>
   <p>Second, as previously noted, the ability of optimizing move assignments
via TR is not merely an enabler for containers; it is also a building
block for trivial swaps and swap-based algorithms. <b>The <code class="highlight"><c- n>container_replace_with_assignment</c-></code> trait is misnamed, and does not
bring the necessary attention to the wanted semantics of a type.</b></p>
   <p>Third, <b>it clashes (and/or has an unknown relationship) with
trivially copyable types</b>, for which containers and algorithms can
already use <code class="highlight"><c- n>memmove</c-></code> in place of move assignments and
construction/destruction.</p>
   <h3 class="heading settled" data-level="6.5" id="instead-of-adding-another-language-facility-for-this-optimization-can-we-use-reflection-instead"><span class="secno">6.5. </span><span class="content">Instead of adding another language facility for this optimization, can we use reflection instead?</span><a class="self-link" href="#instead-of-adding-another-language-facility-for-this-optimization-can-we-use-reflection-instead"></a></h3>
   <p>We are unable to give an accurate answer to this question, as
reflection for C++ is still a pending feature.</p>
   <p>In principle, it certainly sounds possible to use reflection to create
a trait that automatically determines if a type supports TR for move
assignments.</p>
   <p>We would still need a trait in the standard library, so that classes
with user-defined assignment operations can opt-in and declare that
they are optimizable (similar to the <code class="highlight"><c- n>container_replace_with_assignment</c-></code> trait proposed by <a data-link-type="biblio" href="#biblio-p2959r0" title="Container Relocation">[P2959R0]</a>).</p>
   <p>Therefore, the detection should check if the trait has been opted-in;
otherwise, it should check that the type is TR, it has no user-declared
assignment operators, and it has no virtual functions (in other words,
it should use reflection to do what <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a> does through the
language).</p>
   <p>In practice, <strong>we reject a reflection-based approach</strong>:</p>
   <ol>
    <li data-md>
     <p>it is questionable whether this approach has any advantage at all.
Instead of two type properties in the language, we would need a
type property and a customizable type trait in the library;</p>
    <li data-md>
     <p>we would need a very specific feature from reflection, namely, we
need the ability to check whether a class has <em>user-provided
assignment operators</em>.
The current reflection proposal (<a data-link-type="biblio" href="#biblio-p2996r2" title="Reflection for C++26">[P2996R2]</a>) lacks such a query;</p>
    <li data-md>
     <p>we believe that these optimizations are very important to have, and
therefore we do not want to "tie" their availability to the
progress of the reflection proposals.</p>
   </ol>
   <h3 class="heading settled" data-level="6.6" id="can-the-current-model-of-tr-be-extended-to-cover-the-move-assignment-optimizations-in-the-language-at-a-later-stage"><span class="secno">6.6. </span><span class="content">Can the current model of TR be extended to cover the move-assignment optimizations, in the language, <em>at a later stage</em>?</span><a class="self-link" href="#can-the-current-model-of-tr-be-extended-to-cover-the-move-assignment-optimizations-in-the-language-at-a-later-stage"></a></h3>
   <p>As discussed above, the currently model is a strict subset of the one
where TR is allowed for move assignments. It would therefore be
perfectly fine to <em>relax the model</em> or <em>introduce another model</em> (e.g.
another keyword/trait) at a later time.</p>
   <p><b>We are however concerned with the fact that the <em>current</em> proposal is reserving the "trivial relocatable" name/vocabulary to
indicate a <em>subset</em> of the possible use cases for TR</b>. If anything,
it should be using a more restrictive name -- leaving the more generic
"trivial relocation" one for the wider, later proposals.</p>
   <p>As shown above, <strong>existing practice in libraries uses "trivial
relocation" to include move assignments</strong>. It is confusing to introduce
the same terminology into core language, but with a different meaning.</p>
   <h2 class="heading settled" data-level="7" id="lack-of-library-api"><span class="secno">7. </span><span class="content">Lack of library API</span><a class="self-link" href="#lack-of-library-api"></a></h2>
   <p><a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> also features a minimal library API (consisting of a type
trait and a trivial relocation function). Other library extensions are
discussed in the aforementioned <a data-link-type="biblio" href="#biblio-p2959r0" title="Container Relocation">[P2959R0]</a> ("Container Relocation")
and <a data-link-type="biblio" href="#biblio-p2967r0" title="Relocation Is A Library Interface">[P2967R0]</a> ("Relocation Is A Library Interface").</p>
   <h3 class="heading settled" data-level="7.1" id="do-we-know-we-got-the-design-right"><span class="secno">7.1. </span><span class="content">Do we know we got the design right?</span><a class="self-link" href="#do-we-know-we-got-the-design-right"></a></h3>
   <p>Trivial relocation is a feature that first and foremost is an enabler
for some optimizations in the Standard Library (and user code). The
library additions should have been thoroughly analyzed in order to
validate the language changes.</p>
   <p>On the other hand, <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a>'s design has already widespread
precedent and implementation experience.</p>
   <h3 class="heading settled" data-level="7.2" id="libqoi"><span class="secno">7.2. </span><span class="content">Leaving the TR status of Standard Library datatypes as QoI</span><a class="self-link" href="#libqoi"></a></h3>
   <p>We are extremely concerned with the fact that in the adopted design
explicit library support is required in order to consume and create TR
types. That is, a type that needs to be explicitly marked as TR (for
instance, a type that defines its Rule Of Five special member
functions) is <em>required</em> to be composed of TR subobjects; otherwise,
the program is ill-formed.</p>
   <p><strong>Since a lack of the TR keyword will affect program well-formedness,
we strongly believe that this is not an issue that can be left as QoI</strong> in the Standard Library, as it would make programs inherently
non-portable:</p>
<pre class="highlight"><c- c1>// This *completely reasonable* code may or may not compile:</c->

<c- k>struct</c-> <c- nc>S</c-> <c- n>trivially_relocatable</c->
<c- p>{</c->
    <c- n>S</c-><c- p>();</c->
    <c- n>S</c-><c- p>(</c-><c- n>S</c-> <c- o>&amp;&amp;</c-><c- p>);</c->
    <c- o>~</c-><c- n>S</c-><c- p>();</c->

    <c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>ptr</c-><c- p>;</c->
<c- p>};</c->
</pre>
   <p>To make the above portable, one could add a boolean condition
in the argument of the <code class="highlight"><c- n>trivially_relocatable</c-></code> keyword (checking all
the subobjects), but this is extremely vexing and error-prone.</p>
   <h2 class="heading settled" data-level="8" id="what-even-is-relocation"><span class="secno">8. </span><span class="content">What even <strong>is</strong> relocation?</span><a class="self-link" href="#what-even-is-relocation"></a></h2>
   <p>The currently adopted model introduces the "trivial relocatable" type
property <strong>without also formally defining what "relocatable" or
"relocation" means</strong>.</p>
   <p>This is a striking difference with all the other fundamental type
properties, for which there’s a "trivial-less" definition, and the
trivial version means "this can be done, and can be done without
running specialized code" (for instance, "copy constructible" and
"trivially copy constructible"). (The only exception to this pattern
would be "trivially copyable", but this is an "umbrella" property
defined in terms of other properties, which are required to be
trivial.)</p>
   <p>In particular: <b>the adopted model does <em>not</em> state anywhere that a
relocation is a move construction followed by a destruction of the
source object</b>, and therefore a trivial relocation is meant to
achieve the same effects (but since it’s trivial, it can be done by
using <code class="highlight"><c- n>memcpy</c-></code> plus lifetime magic).</p>
   <p>Without a proper definition of "relocatable", it is hard to reason
about what it means in terms of type design, semantics, and its
interactions with copy and move operations. <strong>This is at odds with
existing practice</strong>, where a definition of relocation <em>is</em> provided and
its relation with the other elementary class operations is clear.
(From this point of view, <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a> defines relocation.)</p>
   <p>It is also at odds with the proposed addition of higher-level
algorithms like <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>uninitialized_relocate</c-></code>, which will trivially
relocate TR types and "do something else" for non-TR types, once more
raising questions on the semantic overlaps.</p>
   <h3 class="heading settled" data-level="8.1" id="is-tr-its-own-primitive-operation-on-a-type"><span class="secno">8.1. </span><span class="content">Is TR its own primitive operation on a type?</span><a class="self-link" href="#is-tr-its-own-primitive-operation-on-a-type"></a></h3>
   <p>The currently adopted model allows for types that are TR but are
for instance not movable (or not publicly movable):</p>
<pre class="highlight"><c- k>struct</c-> <c- nc>S</c-> <c- n>trivially_relocatable</c->
<c- p>{</c->
    <c- n>S</c-><c- p>();</c->
    <c- n>S</c-><c- p>(</c-><c- k>const</c-> <c- n>S</c-> <c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>delete</c-><c- p>;</c->
    <c- n>S</c-><c- p>(</c-><c- n>S</c-> <c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>delete</c-><c- p>;</c->
    <c- o>~</c-><c- n>S</c-><c- p>();</c->
<c- p>};</c->
</pre>
   <p>It is very unclear if these types useful in practice — that is, if TR
truly constitutes a new, different primitive operation; or if instead
such types are "abominations".</p>
   <p>If it’s the latter, should the compiler check that a type marked as TR
is also movable and destructible (i.e. supports some form of
non-trivial "relocation")?</p>
   <div class="note" role="note">
    <p>For instance, a different but related example of "abomination" is a
type that is copyable but not movable:</p>
<pre class="highlight"><c- k>struct</c-> <c- nc>CBNM</c->
<c- p>{</c->
    <c- n>CBNM</c-><c- p>();</c->
    <c- n>CBNM</c-><c- p>(</c-><c- k>const</c-> <c- n>CBNM</c-> <c- o>&amp;</c-><c- p>);</c->
    <c- n>CBNM</c-><c- p>(</c-><c- n>CBNM</c-> <c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>delete</c-><c- p>;</c->
<c- p>};</c->
</pre>
    <p>While formally allowed by the language, such a type has very dubious
design and semantics.</p>
   </div>
   <h3 class="heading settled" data-level="8.2" id="why-allowing-for-trivially-copyable-types-that-arent-tr"><span class="secno">8.2. </span><span class="content">Why allowing for trivially copyable types that aren’t TR?</span><a class="self-link" href="#why-allowing-for-trivially-copyable-types-that-arent-tr"></a></h3>
   <p>Symmetrically, it is not entirely clear what is the purpose of allowing
types to be explicitly marked as non-TR, <em>even if they are trivially
copyable</em>:</p>
<pre class="highlight"><c- c1>// What does this *mean*?</c->
<c- k>struct</c-> <c- nc>TC</c-> <c- n>trivially_relocatable</c-><c- p>(</c->false<c- p>)</c->
<c- p>{</c->
    <c- b>int</c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>;</c->
<c- p>};</c->

<c- k>static_assert</c-><c- p>(</c-><c- k>not</c-> <c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>TC</c-><c- o>></c-><c- p>);</c-> <c- c1>// OK</c->
</pre>
   <p>This means that, in the adopted model, <strong>trivial relocatable is not a
strict superset of trivially copyable</strong>.</p>
   <p>This has poor usability for implementors of containers and algorithms,
who already optimize trivially copyable types using <code class="highlight"><c- n>memcpy</c-></code>. In the
adopted model it is not allowed to TR a non-TR type even if it’s
trivially copyable; this will result in vexing "duplicated" code. For
instance:</p>
<pre class="highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
<c- n>vector</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>reallocate_impl</c-><c- p>(</c-><c- b>size_t</c-> <c- n>new_capacity</c-><c- p>)</c->
<c- p>{</c->
    <c- n>assert</c-><c- p>(</c-><c- n>m_size</c-> <c- o>&lt;=</c-> <c- n>new_capacity</c-><c- p>);</c->
    <c- n>T</c-> <c- o>*</c-><c- n>new_storage</c-> <c- o>=</c-> <c- n>allocate</c-><c- p>(</c-><c- n>new_capacity</c-><c- p>);</c->

    <c- c1>// Need to handle TR and TC separately, because it's</c->
    <c- c1>// not allowed to call trivially_relocate on a non-TR type,</c->
    <c- c1>// even if it's TC!</c->
    <c- k>if</c-> <c- k>constexpr</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>)</c-> <c- p>{</c->
        <c- n>std</c-><c- o>::</c-><c- n>trivially_relocate</c-><c- p>(</c-><c- n>m_begin</c-><c- p>,</c-> <c- n>m_begin</c-> <c- o>+</c-> <c- n>m_size</c-><c- p>,</c-> <c- n>new_storage</c-><c- p>);</c->
    <c- p>}</c-> <c- k>else</c-> <c- k>if</c-> <c- k>constexpr</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>)</c-> <c- p>{</c->
        <c- n>std</c-><c- o>::</c-><c- n>memcpy</c-><c- p>(</c-><c- n>new_storage</c-><c- p>,</c-> <c- n>m_begin</c-><c- p>,</c-> <c- n>m_size</c-> <c- o>*</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>));</c->
    <c- p>}</c-> <c- k>else</c-> <c- k>if</c-> <c- k>constexpr</c-> <c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_nothrow_move_constructible_v</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>)</c-> <c- p>{</c->
        <c- n>std</c-><c- o>::</c-><c- n>uninitialized_move</c-><c- p>(</c-><c- n>m_begin</c-><c- p>,</c-> <c- n>m_begin</c-> <c- o>+</c-> <c- n>m_size</c-><c- p>,</c-> <c- n>new_storage</c-><c- p>);</c->
        <c- n>std</c-><c- o>::</c-><c- n>destroy</c-><c- p>(</c-><c- n>m_begin</c-><c- p>,</c-> <c- n>m_begin</c-> <c- o>+</c-> <c- n>m_size</c-><c- p>);</c->
    <c- p>}</c-> <c- k>else</c-> <c- p>{</c->
        <c- c1>// ...</c->
    <c- p>}</c->

    <c- n>deallocate</c-><c- p>(</c-><c- n>m_begin</c-><c- p>);</c->
    <c- n>m_begin</c-> <c- o>=</c-> <c- n>new_storage</c-><c- p>;</c->
    <c- n>m_capacity</c-> <c- o>=</c-> <c- n>new_capacity</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Granted, the adoption of a higher level facility such as <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>uninitialized_relocate</c-></code> may encapsulate and streamline this
logic. The semantic split still presents a burden for reasoning about
types, and therefore we would like to see better justification for it.</p>
   <h3 class="heading settled" data-level="8.3" id="polymorphic"><span class="secno">8.3. </span><span class="content">Unclear behaviors for polymorphic classes</span><a class="self-link" href="#polymorphic"></a></h3>
   <p>Polymorphic classes can be implicitly TR in the currently adopted
model:</p>
<pre class="highlight"><c- k>struct</c-> <c- nc>Base</c->
<c- p>{</c->
    <c- k>virtual</c-> <c- b>void</c-> <c- nf>f</c-><c- p>();</c->
    <c- b>int</c-> <c- n>a</c-><c- p>;</c->
<c- p>};</c->

<c- k>struct</c-> <c- nc>Derived</c-> <c- o>:</c-> <c- n>Base</c->
<c- p>{</c->
    <c- b>void</c-> <c- nf>f</c-><c- p>()</c-> <c- k>override</c-><c- p>;</c->
    <c- b>int</c-> <c- n>b</c-><c- p>;</c->
<c- p>};</c->

<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>Base</c-><c- o>></c-><c- p>);</c->    <c- c1>// OK</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>Derived</c-><c- o>></c-><c- p>);</c-> <c- c1>// OK</c->
</pre>
   <p>The use case for making these types TR is to enable the TR optimization
for vector reallocation: as explained above, a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- n>Base</c-><c- o>></c-></code> can
safely use TR in order to reallocate its storage.</p>
   <p>Unfortunately, in the proposed model <strong>the TR semantics break down when
we try to relocate a single object.</strong> This code is well-formed:</p>
<pre class="highlight"><c- n>Base</c-> <c- o>*</c-><c- n>source</c-> <c- o>=</c-> <c- k>new</c-> <c- n>Derived</c-><c- p>;</c->
<c- n>Base</c-> <c- o>*</c-><c- n>target</c-> <c- o>=</c-> <c- n>allocate</c-><c- p>(</c-><c- k>sizeof</c-><c- p>(</c-><c- n>Base</c-><c- p>));</c->

<c- c1>// What is the behavior here?</c->
<c- n>std</c-><c- o>::</c-><c- n>trivially_relocate</c-><c- p>(</c-><c- n>source</c-><c- p>,</c-> <c- n>source</c-> <c- o>+</c-> <c- mi>1</c-><c- p>,</c-> <c- n>target</c-><c- p>);</c->
</pre>
   <p>We believe that the TR operation should trigger UB; from a certain
point of view, we are destroying a <code class="highlight"><c- n>Derived</c-></code> object, which does not
have a virtual destructor, through a <code class="highlight"><c- n>Base</c-></code> pointer. However, <strong>it is
unclear what is the behavior of this code in the currently approved
model</strong>; again the lack of a precise specification of what it is
meant by relocation makes it hard to reason about this example.</p>
   <p>(It is worth noting that the example’s behavior would still be
questionable even if the classes involved were not of polymorphic
type.)</p>
   <hr>
   <p>Suppose that we further modify the example, and add the missing virtual
destructor:</p>
<pre class="highlight"><c- k>struct</c-> <c- nc>Base</c->
<c- p>{</c->
    <c- k>virtual</c-> <c- o>~</c-><c- n>Base</c-><c- p>()</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
    <c- k>virtual</c-> <c- b>void</c-> <c- nf>f</c-><c- p>();</c->
    <c- b>int</c-> <c- n>a</c-><c- p>;</c->
<c- p>};</c->

<c- k>struct</c-> <c- nc>Derived</c-> <c- o>:</c-> <c- n>Base</c->
<c- p>{</c->
    <c- b>void</c-> <c- nf>f</c-><c- p>()</c-> <c- k>override</c-><c- p>;</c->
    <c- b>int</c-> <c- n>b</c-><c- p>;</c->
<c- p>};</c->

<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>Base</c-><c- o>></c-><c- p>);</c->    <c- c1>// OK</c->
<c- k>static_assert</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>Derived</c-><c- o>></c-><c- p>);</c-> <c- c1>// OK</c->
</pre>
   <p><code class="highlight"><c- n>Base</c-></code> (and thus <code class="highlight"><c- n>Derived</c-></code>) is still implicitly TR, because its
destructor is merely user-declared, not user-provided. The code in the
previous example:</p>
<pre class="highlight"><c- n>Base</c-> <c- o>*</c-><c- n>source</c-> <c- o>=</c-> <c- k>new</c-> <c- n>Derived</c-><c- p>;</c->
<c- n>Base</c-> <c- o>*</c-><c- n>target</c-> <c- o>=</c-> <c- n>allocate</c-><c- p>(</c-><c- k>sizeof</c-><c- p>(</c-><c- n>Base</c-><c- p>));</c->

<c- c1>// Still not ok!</c->
<c- n>std</c-><c- o>::</c-><c- n>trivially_relocate</c-><c- p>(</c-><c- n>source</c-><c- p>,</c-> <c- n>source</c-> <c- o>+</c-> <c- mi>1</c-><c- p>,</c-> <c- n>target</c-><c- p>);</c->
</pre>
   <p>is still extremely problematic, because it is copying the byte
representation of <code class="highlight"><c- n>Derived</c-></code> into a new object of type <code class="highlight"><c- n>Base</c-></code>. In doing
so, <b>the code ends up copying the virtual table pointer from a <code class="highlight"><c- n>Derived</c-></code> instance into a <code class="highlight"><c- n>Base</c-></code> object!</b></p>
   <p>This code will certainly exhibit behavioral issues; for instance, if
someone calls <code class="highlight"><c- n>target</c-><c- o>-></c-><c- n>f</c-><c- p>()</c-></code>, then <code class="highlight"><c- n>Derived</c-><c- o>::</c-><c- n>f</c-><c- p>()</c-></code> will be called, but <code class="highlight"><c- k>this</c-></code> points to a <code class="highlight"><c- n>Base</c-></code> object.</p>
   <p>It would not be too far fetched to state that the TR operation <em>still</em> causes undefined behavior. <strong>This does not seem to be stated anywhere
by the currently adopted model.</strong></p>
   <div class="note" role="note">
    <p>We believe that, at a minimum, the specification for <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>trivially_relocate</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code> should be amended in order to add as a <em>precondition</em> that <code class="highlight"><c- n>T</c-></code> is the most derived type pointed by the
arguments. This precondition is satisfied by <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- n>Base</c-><c- o>></c-></code>, but
it not necessarily is when dealing with single objects.</p>
   </div>
   <p><strong>This example also shows that in the currently adopted
model it is impossible to avoid UB, even when using types that are
automatically TR.</strong> This fact somehow undermines the safety claims of
embracing an enforcement model for TR.</p>
   <h2 class="heading settled" data-level="9" id="enforcementmodel"><span class="secno">9. </span><span class="content">Enforcement model</span><a class="self-link" href="#enforcementmodel"></a></h2>
   <p>The currently adopted model adopts enforcement mechanics for classes
that are manually marked as <code class="highlight"><c- n>trivially_relocatable</c-><c- p>(</c->true<c- p>)</c-></code>: if the class
has virtual bases and/or non-TR subobjects, the program is ill-formed.</p>
   <p>This enforcement exists in order to prevent accidental UB: if a class
is marked as TR, but one of its subobjects does not actually support
trivial relocation, the program is ill-formed rather than exhibiting UB
at runtime.</p>
   <p>For example:</p>
<pre class="highlight"><c- k>struct</c-> <c- nc>SavedFromUB</c-> <c- n>trivially_relocatable</c->
<c- p>{</c->
    <c- n>SavedFromUB</c-><c- p>();</c->
    <c- o>~</c-><c- n>SavedFromUB</c-><c- p>();</c-> <c- c1>// user-defined dtor => need explicit marking</c->

    <c- n>std</c-><c- o>::</c-><c- n>string</c-> <c- n>s</c-><c- p>;</c->  <c- c1>// possible problem</c->
<c- p>};</c->
</pre>
   <p>On some implementations <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>string</c-></code> is not actually TR, because it
contains a self-referential pointer (the "<code class="highlight"><c- n>begin</c-></code> pointer" points into
the SSO buffer). Therefore, on those implementations, the program above
will be ill-formed, because <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>string</c-></code> will not be marked TR there.</p>
   <p>Virtual base classes may also be implemented via self-referential
pointers, and that is why they make a type non TR.</p>
   <p>One can also follow a more formal line of reasoning: if TR is a new
primitive operation in the language, then all the subobjects of a type
must be TR in order for the type to be itself TR.</p>
   <p>Of course, a type with all subobjects of TR type and with no virtual
base classes can still be accidentally marked as TR even if it is not
(again, it may contain self-referential pointers); there is no real way
to prevent this from happening and thus avoid UB.</p>
   <h3 class="heading settled" data-level="9.1" id="what-is-the-cost-benefit-ratio-of-enforcement"><span class="secno">9.1. </span><span class="content">What is the cost/benefit ratio of enforcement?</span><a class="self-link" href="#what-is-the-cost-benefit-ratio-of-enforcement"></a></h3>
   <p>An enforcement policy comes with some associated engineering costs.</p>
   <ul>
    <li data-md>
     <p>Authors of "library types" may split the implementation of a
type in a certain number of sub-objects. This is often (but not
always) done in order to make the implementation compatible with
older C++ standards, which don’t offer language facilities to
streamline the code.</p>
     <ul>
      <li data-md>
       <p>For instance, deleters, comparators, allocators and so on are
usually (privately) inherited from in order to exploit the
Empty Base Optimization; <code class="highlight"><c- p>[[</c-><c- n>no_unique_address</c-><c- p>]]</c-></code> requires C++20.</p>
      <li data-md>
       <p>Containers like <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>variant</c-></code> or <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>optional</c-></code> need to
enable or disable a number of features (<code class="highlight"><c- k>explicit</c-></code> construction, copy operations, move operations, ...) depending
on the type they hold. Therefore, they cannot use <code class="highlight"><c- k>explicit</c-><c- p>(</c-><c- b>bool</c-><c- p>)</c-></code>, contraints, and similar "modern" facilities,
if they need to be compilable in older C++ standards.</p>
       <p>As a concrete example: this is <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>variant</c-></code> from libc++:</p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-><c- p>...</c-> <c- n>_Types</c-><c- o>></c->
  <c- k>class</c-> <c- nc>variant</c->
  <c- o>:</c-> <c- k>private</c-> <c- n>__detail</c-><c- o>::</c-><c- n>__variant</c-><c- o>::</c-><c- n>_Variant_base</c-><c- o>&lt;</c-><c- n>_Types</c-><c- p>...</c-><c- o>></c-><c- p>,</c->
    <c- k>private</c-> <c- n>_Enable_default_constructor</c-><c- o>&lt;</c->
      <c- n>__detail</c-><c- o>::</c-><c- n>__variant</c-><c- o>::</c-><c- n>_Traits</c-><c- o>&lt;</c-><c- n>_Types</c-><c- p>...</c-><c- o>>::</c-><c- n>_S_default_ctor</c-><c- p>,</c->
        <c- n>variant</c-><c- o>&lt;</c-><c- n>_Types</c-><c- p>...</c-><c- o>>></c-><c- p>,</c->
    <c- k>private</c-> <c- n>_Enable_copy_move</c-><c- o>&lt;</c->
      <c- n>__detail</c-><c- o>::</c-><c- n>__variant</c-><c- o>::</c-><c- n>_Traits</c-><c- o>&lt;</c-><c- n>_Types</c-><c- p>...</c-><c- o>>::</c-><c- n>_S_copy_ctor</c-><c- p>,</c->
      <c- n>__detail</c-><c- o>::</c-><c- n>__variant</c-><c- o>::</c-><c- n>_Traits</c-><c- o>&lt;</c-><c- n>_Types</c-><c- p>...</c-><c- o>>::</c-><c- n>_S_copy_assign</c-><c- p>,</c->
      <c- n>__detail</c-><c- o>::</c-><c- n>__variant</c-><c- o>::</c-><c- n>_Traits</c-><c- o>&lt;</c-><c- n>_Types</c-><c- p>...</c-><c- o>>::</c-><c- n>_S_move_ctor</c-><c- p>,</c->
      <c- n>__detail</c-><c- o>::</c-><c- n>__variant</c-><c- o>::</c-><c- n>_Traits</c-><c- o>&lt;</c-><c- n>_Types</c-><c- p>...</c-><c- o>>::</c-><c- n>_S_move_assign</c-><c- p>,</c->
      <c- n>variant</c-><c- o>&lt;</c-><c- n>_Types</c-><c- p>...</c-><c- o>>></c->
  <c- p>{</c->
</pre>
     </ul>
     <p>If the type so produced needs to be manually tagged as TR, one may
need to also add TR tags to all the "detail" types used by the
implementation, because the enforcement policy would forbid to mark
as TR just the "end result".</p>
     <p><strong>It is unknown how vexing this is going to be in practice.</strong> The
currently proposed model should have done extensive experimentation,
and added the results to the proposal.</p>
    <li data-md>
     <p>There is a risk that <strong>legacy code</strong> will constitute a barrier for
TR adoption. Since TR is a new language feature, no code written
before C++26 is already using it. In particular no "Rule of Five"
datatypes will be automatically TR in the proposed model.</p>
     <p>This means that <strong>a type will only be able to become TR when all of
its "dependencies" will have been upgraded to C++26</strong>. If one is
creating a type <code class="highlight"><c- n>T</c-></code> that uses a third-party legacy type <code class="highlight"><c- n>L</c-></code> as data
member, then <code class="highlight"><c- n>T</c-></code> will not be automatically be TR until <code class="highlight"><c- n>L</c-></code>’s
library is upgraded to C++26. If <code class="highlight"><c- n>T</c-></code> is a Rule of Five type,
it cannot be manually marked as TR, because doing so will make the
program ill-formed:</p>
<pre class="highlight"><c- k>struct</c-> <c- nc>T</c-> <c- n>trivially_relocatable</c-> <c- c1>// possible ERROR here</c->
<c- p>{</c->
    <c- c1>// third party types, outside our control:</c->
    <c- n>Lib1</c-><c- o>::</c-><c- n>Foo</c-> <c- n>m_foo</c-><c- p>;</c->
    <c- n>Lib2</c-><c- o>::</c-><c- n>Bar</c-> <c- n>m_bar</c-><c- p>;</c->

    <c- n>T</c-><c- p>();</c->
    <c- o>~</c-><c- n>T</c-><c- p>();</c->
<c- p>};</c->
</pre>
     <p>One could use a conditional form:</p>
<pre class="highlight"><c- k>struct</c-> <c- nc>T</c->
    <c- n>trivially_relocatable</c-><c- p>(</c->
        <c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>Lib1</c-><c- o>::</c-><c- n>Foo</c-><c- o>></c-> <c- o>&amp;&amp;</c->
        <c- n>std</c-><c- o>::</c-><c- n>is_trivially_relocatable_v</c-><c- o>&lt;</c-><c- n>Lib2</c-><c- o>::</c-><c- n>Bar</c-><c- o>></c->
    <c- p>)</c-> <c- c1>// OK, how but tedious is this?</c->
<c- p>{</c->
    <c- n>Lib1</c-><c- o>::</c-><c- n>Foo</c-> <c- n>m_foo</c-><c- p>;</c->
    <c- n>Lib2</c-><c- o>::</c-><c- n>Bar</c-> <c- n>m_bar</c-><c- p>;</c->

    <c- n>T</c-><c- p>();</c->
    <c- o>~</c-><c- n>T</c-><c- p>();</c->
<c- p>};</c->
</pre>
     <p>but this looks vexing. An "automatic opt-in" (invented syntax: <code class="highlight"><c- n>trivially_relocatable</c-><c- p>(</c-><c- k>auto</c-><c- p>)</c-></code>) is not part of the currently adopted
TR model.</p>
     <p>As discussed in <a href="#libqoi">§ 7.2 Leaving the TR status of Standard Library datatypes as QoI</a>, <strong>the Standard Library itself will be
an offender</strong>. In the currently adopted model, the TR status of
library types is left to QoI, which effectively makes it a "legacy
third-party" dependency for user code as far as TR is concerned.</p>
    <li data-md>
     <p>Finally, there is not a proposed way to have an "override
mechanism" in order to manually mark a subobject as TR, in case we
know that <em>it is</em> but the subobject type has not been marked as
such by its author.</p>
   </ul>
   <p>In conclusion: <strong>we are unable to determine the practical impact of the
enforcement model at scale, and therefore whether it constitutes a good
trade-off.</strong></p>
   <h3 class="heading settled" data-level="9.2" id="automatic-tr-is-still-not-entirely-safe"><span class="secno">9.2. </span><span class="content">Automatic TR is still not entirely safe</span><a class="self-link" href="#automatic-tr-is-still-not-entirely-safe"></a></h3>
   <p>In the currently adopted model, TR somehow extends the "Rule of Five"
to the "Rule of Six": a type that declares any of the special 5 member
functions should define or delete them all, <em>and</em> it should have the <code class="highlight"><c- n>trival_relocatable</c-></code> keyword (possibly set to <code class="highlight">false</code>).</p>
   <p>Modern classes that adopts the "Rule of Zero" will naturally be TR if
their subobjects are.</p>
   <p>However, as noted in <a href="#polymorphic">§ 8.3 Unclear behaviors for polymorphic classes</a>, Rule of Zero types may be
automatically TR and yet exhibit UB if they get trivially relocated.
We are not sure if this problem can be addressed.</p>
   <h2 class="heading settled" data-level="10" id="p1144s-trivial-relocation-model"><span class="secno">10. </span><span class="content">P1144’s trivial relocation model</span><a class="self-link" href="#p1144s-trivial-relocation-model"></a></h2>
   <p><a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a> is an alternative proposal for trivial relocation. Its TR
model differs from the currently adopted one in many (small) ways;
please refer to <a data-link-type="biblio" href="#biblio-p2814r0" title="Trivial Relocatability --- Comparing P1144 with P2786">[P2814R0]</a> for a very detailed comparison.</p>
   <p>A key summary of <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a>'s mechanics for its TR model is:</p>
   <ul>
    <li data-md>
     <p>just like the currently adopted model, introduce "trivially
relocatable" as a type property, for scalars, TR classes, arrays of
TR types and cv-qualified versions;</p>
    <li data-md>
     <p>a class can be marked as TR (or not) by using an attribute
(<code class="highlight"><c- p>[[</c-><c- n>trivially_relocatable</c-><c- p>]]</c-></code>), with an optional boolean argument;</p>
    <li data-md>
     <p>a class is automatically TR if:</p>
     <ul>
      <li data-md>
       <p>all of its subobjects are of TR type or of reference type; and</p>
      <li data-md>
       <p>none of its eligible copy operations, move operations, or destructor are user-provided;</p>
      <li data-md>
       <p>it has no virtual bases; and</p>
      <li data-md>
       <p>no virtual member functions;</p>
     </ul>
    <li data-md>
     <p>there is no enforcement: a class can be manually marked as TR, even
if some of the subobjects are not TR.</p>
   </ul>
   <h3 class="heading settled" data-level="10.1" id="overall-differences-between-p2786-and-p1144"><span class="secno">10.1. </span><span class="content">Overall differences between P2786 and P1144</span><a class="self-link" href="#overall-differences-between-p2786-and-p1144"></a></h3>
   <p>The "mechanical" differences between <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> and <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a>'s TR
models are summarized in this table:</p>
   <table>
    <thead>
     <tr>
      <th>
      <th>
      <th>P2786
      <th>P1144
    <tbody>
     <tr>
      <th>Type property
      <th>
      <td colspan="2">"Trivially relocatable": scalars, TR classes, arrays of TR, and cv-qualified TR
     <tr>
      <th>TR tag
      <th>
      <td>Contextual keyword: <code class="highlight"><c- n>trivially_relocatable</c-><c- p>(</c-><c- b>bool</c-><c- p>)</c-></code>
      <td>Attribute: <code class="highlight"><c- p>[[</c-><c- n>trivially_relocatable</c-><c- p>(</c-><c- b>bool</c-><c- p>)]]</c-></code>
     <tr>
      <th rowspan="7">A class is automatically TR if?
      <td>Subobjects
      <td colspan="2">Must be of TR or reference type
     <tr>
      <td>Destructor
      <td>Not deleted, not user-provided
      <td>If eligible, not user-provided
     <tr>
      <td>Copy/move ctor
      <td>Type must be move constructible via a non-deleted non-user-provided constructor
      <td>If eligible, not user-provided
     <tr>
      <td>Copy/move assign
      <td>Irrelevant
      <td>If eligible, not user-provided
     <tr>
      <td>Virtual bases
      <td>Not allowed
      <td>Not allowed
     <tr>
      <td>Virtual member functions
      <td>Allowed
      <td>Not allowed
     <tr>
      <td>TR tag
      <td>Must not be present
      <td>Irrelevant
     <tr>
      <th>TC¹ implies TR
      <th>
      <td>No
      <td>Yes
     <tr>
      <th>Enforcement of TR tags
      <th>
      <td>Yes
      <td>No
   </table>
   <div class="note" role="note">
    <p>¹ Trivial Copyability</p>
   </div>
   <h3 class="heading settled" data-level="10.2" id="p1144s-tr-semantics"><span class="secno">10.2. </span><span class="content">P1144’s TR semantics</span><a class="self-link" href="#p1144s-tr-semantics"></a></h3>
   <p>Once more, we are not interested in comparing the exact shape of the
APIs proposed, and we will try to focus instead on what kind design
P1144 allows for.</p>
   <p>P1144’s requirements for TR types are <em>more strict</em> than the currently
adopted proposal. (Or, vice versa: the currently adopted proposals
"accepts" by default more types than P1144.) In particular, in P1144’s
model, types with user-provided assignment operations and types with
virtual member functions are <strong>not</strong> automatically TR.</p>
   <p><strong>The reason for these additional restrictions is that P1144’s TR
semantics is also meant to cover assignments</strong>: in this model, a move
assignment on a relocatable type is assumed to be equivalent to
destruction of the target and move construction of the source. In other
words, relocatable types have "value semantics" for assignments. This
is important because it unlocks the <a href="#missingoptimizations">additional
optimizations</a> that we have discussed earlier, optimizations that are
unavailable in the currently adopted model.</p>
   <div class="note" role="note">
    <p>This equivalence of move assignment with destruction and move
construction is enshrined by the semantic requirements of the proposed <code class="highlight"><c- n>relocatable</c-></code> concept; cf. §4.7 in <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a>.</p>
   </div>
   <p>If the user provides an assignment operator then we can no longer
assume its semantics (it may have reference semantics), and therefore
the type can no longer be automatically TR.</p>
   <p>The presence of virtual functions also disables automatic TR, because
in case the type gets sliced (by move construction or move assignment)
then the virtual table pointer cannot be copied using a <code class="highlight"><c- n>memcpy</c-></code>.</p>
   <h4 class="heading settled" data-level="10.2.1" id="trivially-copyable-always-implies-automatically-trivially-relocatable"><span class="secno">10.2.1. </span><span class="content">Trivially copyable always implies automatically trivially relocatable</span><a class="self-link" href="#trivially-copyable-always-implies-automatically-trivially-relocatable"></a></h4>
   <p>In P1144’s model the requirements for begin automatic TR are always
satisfied by trivially copyable types. In contrast, in the currently
adopted model, it is possible to have trivially copyable types that are <em>not</em> trivially relocatable.</p>
   <p>A trivially copyable type may be missing some special operation; for
instance, it may be not move constructible or not assignable:</p>
<pre class="highlight"><c- k>struct</c-> <c- nc>TC</c-> <c- p>{</c->
    <c- n>TC</c-><c- p>();</c->
    <c- n>TC</c-><c- p>(</c-><c- k>const</c-> <c- n>TC</c-> <c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
    <c- n>TC</c-><c- p>(</c-><c- n>TC</c-> <c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
    <c- n>TC</c-> <c- o>&amp;</c-><c- k>operator</c-><c- o>=</c-><c- p>(</c-><c- k>const</c-> <c- n>TC</c-> <c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>delete</c-><c- p>;</c->
    <c- n>TC</c-> <c- o>&amp;</c-><c- k>operator</c-><c- o>=</c-><c- p>(</c-><c- n>TC</c-> <c- o>&amp;&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>delete</c-><c- p>;</c->
    <c- o>~</c-><c- n>TC</c-><c- p>()</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- p>};</c->

<c- k>static_assert</c-><c- p>(</c->    <c- n>std</c-><c- o>::</c-><c- n>is_trivially_copyable_v</c-><c- o>&lt;</c-><c- n>TC</c-><c- o>></c-><c- p>);</c->
<c- k>static_assert</c-><c- p>(</c-><c- k>not</c-> <c- n>std</c-><c- o>::</c-><c- n>is_move_assignable_v</c-><c- o>&lt;</c-><c- n>TC</c-><c- o>></c-><c- p>);</c->
</pre>
   <p>P1144 still considers those types to be TR. However, the APIs that make
use of relocation may refuse to work with such types: <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-></code> still requires to <code class="highlight"><c- n>push_back</c-></code> a non-movable type, and the proposed <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>relocate_at</c-></code> building block effectively <em>Mandates</em> the type to be
move constructible.</p>
   <h4 class="heading settled" data-level="10.2.2" id="tr-is-an-intrinsic-quality"><span class="secno">10.2.2. </span><span class="content">TR is an intrinsic quality</span><a class="self-link" href="#tr-is-an-intrinsic-quality"></a></h4>
   <p>If a type satisfies all the criteria for being automatically TR, then
in P1144’s model the type <strong>is</strong> TR, even if marked <code class="highlight"><c- p>[[</c-><c- n>trivially_relocatable</c-><c- p>(</c->false<c- p>)]]</c-></code>. This makes it impossible to create
a type which is trivially copyable, and yet not trivially relocatable.</p>
   <p>We are not sure if P1144’s intention is to have implementations issue
QoI diagnostics for such types.</p>
   <h4 class="heading settled" data-level="10.2.3" id="trivially-copyable-types-are-a-subset-of-trivially-relocatable"><span class="secno">10.2.3. </span><span class="content">Trivially copyable types are a subset of trivially relocatable</span><a class="self-link" href="#trivially-copyable-types-are-a-subset-of-trivially-relocatable"></a></h4>
   <p>If we combine the last two considerations together, we can conclude
that in P1144’s model trivial copyable types are always a subset of
trivial relocatable types. Of course the interesting cases are types
that are <em>not</em> trivially copyable but only TR (e.g. "Rule Of Five"
types like <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>); these are supposed to be manually
marked. This means that the subset is also proper.</p>
   <p><strong>This result has a practical application: generic that wants to apply
TR-related optimizations can use TR to also handle trivially copyable
types.</strong></p>
   <h3 class="heading settled" data-level="10.3" id="which-optimizations-are-possible-in-p1144s-model"><span class="secno">10.3. </span><span class="content">Which optimizations are possible in P1144’s model?</span><a class="self-link" href="#which-optimizations-are-possible-in-p1144s-model"></a></h3>
   <p>Since P1144 is more strict than the currently adopted proposal, it
allows for more optimization opportunites. In particular, it unlocks
both family of optimizations discussed above:</p>
   <ul>
    <li data-md>
     <p>vector reallocation can get optimized, just like in the adopted
model, as discussed in <a href="#vectorreallocate">§ 5 What optimizations are possible in the current model?</a>;</p>
    <li data-md>
     <p>optimizations for move assignments are also enabled:
vector <code class="highlight"><c- n>erase</c-></code> and <code class="highlight"><c- n>insert</c-></code>; <code class="highlight"><c- n>swap</c-></code>; and swap-based algorithms
(as discussed in <a href="#missingoptimizations">§ 6 The missing optimizations</a>).</p>
   </ul>
   <h3 class="heading settled" data-level="10.4" id="which-optimizations-are-not-possible-in-p1144s-model"><span class="secno">10.4. </span><span class="content">Which optimizations are <strong>not possible</strong> in P1144’s model?</span><a class="self-link" href="#which-optimizations-are-not-possible-in-p1144s-model"></a></h3>
   <p>Types for which move assignement is not equivalent to destruction of
the target and move construction from the source are not considered to
be TR in P1144’s model. As discussed in <a href="#troptimizationformoveassignment">§ 6.1 Why are TR optimizations for move assignments not allowed?</a>, examples of these types include <code class="highlight"><c- n>IRef</c-></code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- b>int</c-> <c- o>&amp;></c-></code>, as well as types such as <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>pmr</c-><c- o>::</c-><c- n>string</c-></code>.</p>
   <p><b>This means that in P1144’s model a vector of <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>pmr</c-><c- o>::</c-><c- n>string</c-></code> will not be able to exploit TR when it reallocates.</b></p>
   <hr>
   <p><b>This is the "split" that we were referring to in the <a href="#introduction">§ 2 Introduction</a> chapter</b>: this perfectly reasonable optimization
is possible only in rthe currently adopted model, but not in P1144’s;
while instead optimizing insertion, erasure, sorting, etc. of a <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>></c-></code> is only possible in P1144 but not in
the currently adopted model.</p>
   <p>There does not seem to be any technical reason as of why <em>both</em> optimizations shouldn’t be available instead; the only obstacle seems
to be on how to "offer" these facilities (and, thus, concerns
relative to naming, teachability, discoverability).</p>
   <h2 class="heading settled" data-level="11" id="summary"><span class="secno">11. </span><span class="content">Summary</span><a class="self-link" href="#summary"></a></h2>
   <p>We have identified two different trivial relocation models, that
enable very different optimization possibilities:</p>
   <table>
    <thead>
     <tr>
      <th>Model
      <th>Optimizes
      <th>Enabled by
    <tbody>
     <tr>
      <td>1. Move construction and destruction of the source object can be achieved via <code class="highlight"><c- n>memcpy</c-></code> for a TR type
      <td> Vector reallocation 
      <td>Both P2786 and P1144
     <tr>
      <td>2. Like 1., <i>and</i>, TR types have value semantics: move assignment followed by destruction of the source is equivalent to destruction of the target and relocation
      <td> Vector reallocation, <code class="highlight"><c- n>insert</c-></code>, <code class="highlight"><c- n>erase</c-></code>;<br> <code class="highlight"><c- n>swap</c-></code>;<br> swap-based algorithms (e.g. <code class="highlight"><c- n>sort</c-></code>, <code class="highlight"><c- n>rotate</c-></code>) 
      <td> P1144 only (<em>unacceptable library solution provided by P2959</em>) 
   </table>
   <p>The currently adopted model only allows for n° 1.</p>
   <hr>
   <p>This table summarizes the support for non-trivially copyable types
on popular implementations:</p>
   <table>
    <thead>
     <tr>
      <th>Type
      <th>TR for move construction only?
      <th>TR for move construction and assignment?¹
      <th>Notes
    <tbody>
     <tr>
      <th><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>string</c-></code>
      <td>🟡
      <td>🟡
      <td>On some implementations it is self-referential.
     <tr>
      <th><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>shared_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>
      <td>✅
      <td>✅
      <td>
     <tr>
      <th><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>optional</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>, <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>variant</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>
      <td>✅
      <td>✅
      <td>Provided that <code class="highlight"><c- n>T</c-></code> is a type with the same TR capabilities
     <tr>
      <th><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>
      <td>✅
      <td>✅
      <td>
     <tr>
      <th><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>list</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-></code>
      <td>🟡
      <td>🟡
      <td>On some implementations it is self-referential.
     <tr>
      <th><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>tuple</c-><c- o>&lt;</c-><c- n>T</c-> <c- o>&amp;></c-></code>
      <td>✅
      <td>❌
      <td>The assignment operator implements reference semantics.
     <tr>
      <th><code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>pmr</c-><c- o>::</c-><c- n>string</c-></code>
      <td>✅
      <td>❌
      <td>The allocator is not assignable.
     <tr>
      <th>Polymorphic types
      <td>✅ (???)
      <td>❌
      <td>Slicing <a href="#polymorphic">may introduce UB</a>. However, normally polymorphic types are not movable nor assignable.
   </table>
   <div class="note" role="note">
    <p>¹ Note: the second column always implies (generalizes) the first.</p>
   </div>
   <h2 class="heading settled" data-level="12" id="a-possible-way-forward"><span class="secno">12. </span><span class="content">A possible way forward</span><a class="self-link" href="#a-possible-way-forward"></a></h2>
   <h3 class="heading settled" data-level="12.1" id="disclaimer"><span class="secno">12.1. </span><span class="content">Disclaimer</span><a class="self-link" href="#disclaimer"></a></h3>
   <p>We would like to ask forgiveness in advance for our sin: it is very
presumptuous of us to propose ideas, but then ask others to actually do
the work to support these ideas.</p>
   <p>As we mentioned in the <a href="#introduction">§ 2 Introduction</a> chapter, we are only sketching
a possible plan to reconcile the two TR proposals. The plan that we put
forward is very bold, and we certainly understand if readers are
skeptical about its feasibility.</p>
   <h3 class="heading settled" data-level="12.2" id="proposed-action-points"><span class="secno">12.2. </span><span class="content">Proposed action points</span><a class="self-link" href="#proposed-action-points"></a></h3>
   <ul>
    <li data-md>
     <p><b>We strongly urge EWG and LEWG to reconsider the adoption of <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a> as the model for trivial relocation in C++.</b></p>
    <li data-md>
     <p><strong>Ideally, the two TR proposals should be merged into one.</strong></p>
     <ul>
      <li data-md>
       <p>If this is not possible or not wanted, then we would prefer <a data-link-type="biblio" href="#biblio-p1144r10" title="std::is_trivially_relocatable">[P1144R10]</a> for C++26 instead of <a data-link-type="biblio" href="#biblio-p2786r4" title="Trivial Relocatability For C++26">[P2786R4]</a>.</p>
     </ul>
    <li data-md>
     <p><strong>The merged proposal should give proper name and semantics</strong> to:</p>
     <ol>
      <li data-md>
       <p>the combined "move construction + destruction of the source"
operation (relocation? destroying move?); and</p>
      <li data-md>
       <p>the type property that describes that, for a given type, "move
assignment + destruction of the source" is equivalent to
"destruction of the target + move construction + destruction of
the source" (that is, is equivalent to "destruction of the
target + relocation").</p>
     </ol>
    <li data-md>
     <p><strong>The merged proposal should have two language enablers</strong>:</p>
     <ul>
      <li data-md>
       <p>one that enables trivial destroying-move and only that; and</p>
      <li data-md>
       <p>one that enables it, and says that a type has the type property
described above.</p>
     </ul>
    <li data-md>
     <p><strong>The latter enabler should have the simpler, more generic name</strong>;
most TR types will want to use that enabler.</p>
     <ul>
      <li data-md>
       <p>This is important for teachability and discoverability of the
feature.</p>
      <li data-md>
       <p>We believe that "trivially copyable" is the precedent to
follow here, in the sense that it’s the type trait that
is actually useful and has a very simple name. Its
building blocks, like "trivially copy constructible", have
longer/uglier names.</p>
     </ul>
    <li data-md>
     <p>Since we are proposing <em>two</em> language enablers, <strong>an attribute
sounds more appetizing than two keywords</strong>. However, if enforcement
semantics are wanted, the current stance on attribute ignorability
requires the proposal to add keywords.</p>
    <li data-md>
     <p>Given that we are adding a tool that removes "Undefined Behavior
That Works In Practice", but adds another source of UB, <strong>we would
like to have SG12’s expressed vote on whether TR should embrace
enforcement or not</strong>.</p>
     <ul>
      <li data-md>
       <p>The pros and cons of having an enforcement model should be
clearly analyzed before choosing which direction to follow;
we offered some starting points for discussion in the <a href="#enforcementmodel">§ 9 Enforcement model</a> chapter.</p>
     </ul>
    <li data-md>
     <p><strong>Language and library must be dealt with in the very same proposal</strong>.
At a minimum, the library utilities with the biggest impact should be
included.</p>
     <ul>
      <li data-md>
       <p>That includes for instance <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>uninitialized_relocate</c-></code>, as
it’s the API that everyone will want to use.</p>
      <li data-md>
       <p>If enforcement is wanted, then the proposal <strong>must</strong> also include <em>all</em> of the Standard Library datatypes that won’t be automatically
TR and thus need manual marking. TR should not ship in C++26
unless the Standard Library is also ready for it. Leaving the TR
status of the Standard Library to QoI makes for a poorly cooked
feature.</p>
     </ul>
   </ul>
   <h2 class="heading settled" data-level="13" id="acknowledgements"><span class="secno">13. </span><span class="content">Acknowledgements</span><a class="self-link" href="#acknowledgements"></a></h2>
   <p>Thanks to KDAB for supporting this work.</p>
   <p>All remaining errors are ours and ours only.</p>
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

  var sidebarMedia = window.matchMedia('screen and (min-width: 78em)');
  var autoToggle   = function(e){ toggleSidebar(e.matches) };
  if(sidebarMedia.addListener) {
    sidebarMedia.addListener(autoToggle);
  }

  function toggleSidebar(on) {
    if (on == undefined) {
      on = !document.body.classList.contains('toc-sidebar');
    }

    /* Don't scroll to compensate for the ToC if we're above it already. */
    var headY = 0;
    var head = document.querySelector('.head');
    if (head) {
      // terrible approx of "top of ToC"
      headY += head.offsetTop + head.offsetHeight;
    }
    var skipScroll = window.scrollY < headY;

    var toggle = document.getElementById('toc-toggle');
    var tocNav = document.getElementById('toc');
    if (on) {
      var tocHeight = tocNav.offsetHeight;
      document.body.classList.add('toc-sidebar');
      document.body.classList.remove('toc-inline');
      toggle.innerHTML = collapseSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, 0 - tocHeight);
      }
      tocNav.focus();
      sidebarMedia.addListener(autoToggle); // auto-collapse when out of room
    }
    else {
      document.body.classList.add('toc-inline');
      document.body.classList.remove('toc-sidebar');
      toggle.innerHTML = expandSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, tocNav.offsetHeight);
      }
      if (toggle.matches(':hover')) {
        /* Unfocus button when not using keyboard navigation,
           because I don't know where else to send the focus. */
        toggle.blur();
      }
    }
  }

  function createSidebarToggle() {
    /* Create the sidebar toggle in JS; it shouldn't exist when JS is off. */
    var toggle = document.createElement('a');
      /* This should probably be a button, but appearance isn't standards-track.*/
    toggle.id = 'toc-toggle';
    toggle.class = 'toc-toggle';
    toggle.href = '#toc';
    toggle.innerHTML = collapseSidebarText;

    sidebarMedia.addListener(autoToggle);
    var toggler = function(e) {
      e.preventDefault();
      sidebarMedia.removeListener(autoToggle); // persist explicit off states
      toggleSidebar();
      return false;
    }
    toggle.addEventListener('click', toggler, false);


    /* Get <nav id=toc-nav>, or make it if we don't have one. */
    var tocNav = document.getElementById('toc-nav');
    if (!tocNav) {
      tocNav = document.createElement('p');
      tocNav.id = 'toc-nav';
      /* Prepend for better keyboard navigation */
      document.body.insertBefore(tocNav, document.body.firstChild);
    }
    /* While we're at it, make sure we have a Jump to Toc link. */
    var tocJump = document.getElementById('toc-jump');
    if (!tocJump) {
      tocJump = document.createElement('a');
      tocJump.id = 'toc-jump';
      tocJump.href = '#toc';
      tocJump.innerHTML = tocJumpText;
      tocNav.appendChild(tocJump);
    }

    tocNav.appendChild(toggle);
  }

  var toc = document.getElementById('toc');
  if (toc) {
    createSidebarToggle();
    toggleSidebar(sidebarMedia.matches);

    /* If the sidebar has been manually opened and is currently overlaying the text
       (window too small for the MQ to add the margin to body),
       then auto-close the sidebar once you click on something in there. */
    toc.addEventListener('click', function(e) {
      if(e.target.tagName.toLowerCase() == "a" && document.body.classList.contains('toc-sidebar') && !sidebarMedia.matches) {
        toggleSidebar(false);
      }
    }, false);
  }
  else {
    console.warn("Can't find Table of Contents. Please use <nav id='toc'> around the ToC.");
  }

  /* Wrap tables in case they overflow */
  var tables = document.querySelectorAll(':not(.overlarge) > table.data, :not(.overlarge) > table.index');
  var numTables = tables.length;
  for (var i = 0; i < numTables; i++) {
    var table = tables[i];
    var wrapper = document.createElement('div');
    wrapper.className = 'overlarge';
    table.parentNode.insertBefore(wrapper, table);
    wrapper.appendChild(table);
  }

})();
</script>
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-p1144r10">[P1144R10]
   <dd>Arthur O'Dwyer. <a href="https://wg21.link/p1144r10"><cite>std::is_trivially_relocatable</cite></a>. 15 February 2024. URL: <a href="https://wg21.link/p1144r10">https://wg21.link/p1144r10</a>
   <dt id="biblio-p2786r4">[P2786R4]
   <dd>Mungo Gill, Alisdair Meredith. <a href="https://wg21.link/p2786r4"><cite>Trivial Relocatability For C++26</cite></a>. 9 February 2024. URL: <a href="https://wg21.link/p2786r4">https://wg21.link/p2786r4</a>
   <dt id="biblio-p2814r0">[P2814R0]
   <dd>Mungo Gill, Alisdair Meredith; Arthur O`Dwyer. <a href="https://wg21.link/p2814r0"><cite>Trivial Relocatability --- Comparing P1144 with P2786</cite></a>. 19 May 2023. URL: <a href="https://wg21.link/p2814r0">https://wg21.link/p2814r0</a>
   <dt id="biblio-p2959r0">[P2959R0]
   <dd>Alisdair Meredith. <a href="https://wg21.link/p2959r0"><cite>Container Relocation</cite></a>. 15 October 2023. URL: <a href="https://wg21.link/p2959r0">https://wg21.link/p2959r0</a>
   <dt id="biblio-p2967r0">[P2967R0]
   <dd>Alisdair Meredith. <a href="https://wg21.link/p2967r0"><cite>Relocation Is A Library Interface</cite></a>. 15 October 2023. URL: <a href="https://wg21.link/p2967r0">https://wg21.link/p2967r0</a>
   <dt id="biblio-p2996r2">[P2996R2]
   <dd>Barry Revzin, Wyatt Childers, Peter Dimov, Andrew Sutton, Faisal Vali, Daveed Vandevoorde, Dan Katz. <a href="https://wg21.link/p2996r2"><cite>Reflection for C++26</cite></a>. 15 February 2024. URL: <a href="https://wg21.link/p2996r2">https://wg21.link/p2996r2</a>
  </dl>