<!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>P2123R0: Extending the Type System to Provide API and ABI Flexibility</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
 *
 * 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)
 *   - .assertion  for assertions                    (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *
 * 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
 *
 * 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)
 *
 ******************************************************************************/

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

	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;

		/* Colors */
		color: black;
		background: white 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-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		color: white;
		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;
		border-color: #c00;
	}

	/* 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: 2;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
			color: black;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

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

			background: white;
			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;
			background: white;
		}
		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		#toc-nav > a:hover,
		#toc-nav > a:focus {
			background: #f8f8f8;
		}
		#toc-nav > a:not(:hover):not(:focus) {
			color: #707070;
		}

		/* 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-toggle-inline {
			vertical-align: 0.05em;
			font-size: 80%;
			color: gray;
			color: hsla(203,20%,40%,.7);
			border-style: none;
			background: transparent;
			position: relative;
		}
		#toc-toggle-inline:hover:not(:active),
		#toc-toggle-inline:focus:not(:active) {
			text-shadow: 1px 1px silver;
			top: -1px;
			left: -1px;
		}

		#toc-nav :active {
			color: #C00;
		}
	}

/** 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);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) 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);
		}
		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);
			background: inherit;
			background-color: #f7f8f9;
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) 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);
		}

		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;
		background: transparent;
	}

	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,
	#subtitle {
		/* #subtitle 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) > hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		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;
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	  padding: .5em;
	  border: thin solid #ddd; 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: medium;
	}
	dfn var {
		font-style: normal;
	}

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

	del { color: red;  text-decoration: line-through; }
	ins { color: #080; text-decoration: underline;    }

/** 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;
		page-break-inside: avoid;
		hyphens: none;
		text-transform: none;
	}
	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;
		text-decoration: none;
		border-bottom: 1px solid #707070;
		/* Need a bit of extending for it to look okay */
		padding: 0 1px 0;
		margin: 0 -1px 0;
	}
	a:visited {
		border-bottom-color: #BBB;
	}

	/* Use distinguishing colors when user is interacting with the link */
	a[href]:focus,
	a[href]:hover {
		background: #f8f8f8;
		background: rgba(75%, 75%, 75%, .25);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	a[href]:active {
		color: #C00;
		border-color: #C00;
	}

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

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

	img {
		border-style: none;
	}

	/* 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;
	}
	.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 {
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	.issue,
	.note,
	.example,
	.advisement,
	.assertion,
	blockquote {
		margin: 1em auto;
	}
	.note  > p:first-child,
	.issue > p:first-child,
	blockquote > :first-child {
		margin-top: 0;
	}
	blockquote > :last-child {
		margin-bottom: 0;
	}

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

	blockquote {
		border-color: silver;
	}

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

	.issue {
		border-color: #E05252;
		background: #FBE9E9;
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		text-transform: uppercase;
		color: #AE1E1E;
		padding-right: 1em;
		text-transform: uppercase;
	}
	/* 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;
		background: #FCFAEE;
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		text-transform: uppercase;
		color: #827017;
		min-width: 7.5em;
		display: block;
	}
	/* 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;
		background: #E9FBE9;
		overflow: auto;
	}

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

	details.note > summary {
		display: block;
		color: hsl(120, 70%, 30%);
	}
	details.note[open] > summary {
		border-bottom: 1px silver solid;
	}

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

	.assertion {
		border-color: #AAA;
		background: #EEE;
	}

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

	.advisement {
		border-color: orange;
		border-style: none solid;
		background: #FFEECC;
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement > .marker {
		color: #B35F00;
	}

/** 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: #fdd;
		color: red;
		font-weight: bold;
		padding: .75em 1em;
		border: thick red;
		border-style: solid;
		border-radius: 1em;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

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

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

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

	.def {
		padding: .5em 1em;
		background: #DEF;
		margin: 1.2em 0;
		border-left: 0.5em solid #8CCBF2;
	}

/******************************************************************************/
/*                                    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;
	}

	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-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;
		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;
		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-top: 0.1rem;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Reverse color scheme */
		color: black;
		border-color: #3980B5;
		border-bottom-width: 3px !important;
		margin-bottom: 0px !important;
	}
	.toc a:visited {
		border-color: #054572;
	}
	.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;
		line-height: 1.1rem; /* consistent spacing */
	}

	/* 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 .secno { font-size: 85%; }
	.toc > li li li li li { font-size:   85%;    }
	.toc > li li li li li .secno { font-size: 100%; }

	/* @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 {
			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; }
		}
	/* } */

	@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;
		}
		#toc .content:hover {
			background: rgba(75%, 75%, 75%, .25);
			border-bottom: 3px solid #054572;
			margin-bottom: -3px;
		}
		#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 span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
		}
	}

/** 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]) {
		background: #f7f8f9;
	}

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

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

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

/******************************************************************************/
/*                                    Legacy                                  */
/******************************************************************************/

	/* This rule is inherited from past style sheets. No idea what it's for. */
	.hide { display: none }



/******************************************************************************/
/*                             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 > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-left: calc(13px + 26.5rem - 50vw);
			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-left: calc(40em - 50vw) !important;
			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-left: 0 !important;
			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 type="text/css">
    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 2dbd5e1f0bb11704a5d90167ddaef9475f9c26b3" name="generator">
  <link href="http://wg21.link/p2123" rel="canonical">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
  <meta content="a26cd28b782622cfcfae0b5881b98a2bd743b193" name="document-revision">
<style>/* 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>/* 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>/* style-syntax-highlighting */

.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }
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 */
</style>
<style>/* style-selflinks */

.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%;
}
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: gray;
    color: white;
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: black;
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }</style>
<style>/* style-autolinks */

.css.css, .property.property, .descriptor.descriptor {
    color: #005a9c;
    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;
}</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P2123R0<br>Extending the Type System to Provide API and ABI Flexibility</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Published Proposal, <time class="dt-updated" datetime="2020-03-02">2020-03-02</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="http://wg21.link/p2123">http://wg21.link/p2123</a>
     <dt>Issue Tracking:
     <dd><a href="#issues-index">Inline In Spec</a>
     <dt>Authors:
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:hfinkel@anl.gov">Hal Finkel</a> (<span class="p-org org">Argonne National Laboratory</span>)
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:scogland1@llnl.gov">Tom Scogland</a> (<span class="p-org org">Lawrence Livermore National Laboratory</span>)
     <dt>Audience:
     <dd>SG17
     <dt>Project:
     <dd>ISO/IEC JTC1/SC22/WG21 14882: Programming Language — C++
    </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>For C++, in some collective sense, our community wants the flexibility to change the implementation details and interfaces of types in order to realize performance benefits and otherwise enhance functionality while simultaneously wanting the interface stability necessary to compose software from compiled code created by multiple entities over long time spans. C++ does not currently provide the language-level tools necessary in order to express different points in this flexibility vs. stability space, and this makes it increasingly difficult to evolve the language and its standard library in useful directions. In this paper, we’ll explore requirements and a potential solution to this problem.</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="#intro"><span class="secno">1</span> <span class="content">Introduction</span></a>
    <li><a href="#chlog"><span class="secno">2</span> <span class="content">Changelog</span></a>
    <li><a href="#impl"><span class="secno">3</span> <span class="content">Implementation</span></a>
    <li><a href="#what"><span class="secno">4</span> <span class="content">What Are We Talking About?</span></a>
    <li><a href="#whatnot"><span class="secno">5</span> <span class="content">What Are We Not Talking About?</span></a>
    <li><a href="#costs"><span class="secno">6</span> <span class="content">On Costs</span></a>
    <li><a href="#paste"><span class="secno">7</span> <span class="content">Some Past Experience</span></a>
    <li><a href="#jrc"><span class="secno">8</span> <span class="content">Just Recompile!</span></a>
    <li><a href="#helpw"><span class="secno">9</span> <span class="content">Does This Help With ...</span></a>
    <li><a href="#req"><span class="secno">10</span> <span class="content">Requirements</span></a>
    <li><a href="#diffex"><span class="secno">11</span> <span class="content">Differences From Existing Features</span></a>
    <li><a href="#olang"><span class="secno">12</span> <span class="content">Other Languages</span></a>
    <li><a href="#hdi"><span class="secno">13</span> <span class="content">How Do I?</span></a>
    <li><a href="#odr"><span class="secno">14</span> <span class="content">ODR and Definition Flexibility</span></a>
    <li>
     <a href="#prop"><span class="secno">15</span> <span class="content">Proposal</span></a>
     <ol class="toc">
      <li><a href="#itags"><span class="secno">15.1</span> <span class="content">Interface Tags</span></a>
      <li><a href="#blks"><span class="secno">15.2</span> <span class="content">Interface Blocks</span></a>
      <li>
       <a href="#quals"><span class="secno">15.3</span> <span class="content">Interface Qualifiers</span></a>
       <ol class="toc">
        <li><a href="#qualsadd"><span class="secno">15.3.1</span> <span class="content">Interface Additivity</span></a>
        <li><a href="#qualsur"><span class="secno">15.3.2</span> <span class="content">Unresolved Interfaces</span></a>
       </ol>
      <li><a href="#hdr"><span class="secno">15.4</span> <span class="content">Header &lt;stdinterface></span></a>
     </ol>
    <li><a href="#ack"><span class="secno">16</span> <span class="content">Acknowledgments</span></a>
    <li><a href="#issues-index"><span class="secno"></span> <span class="content">Issues Index</span></a>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="intro"><span class="secno">1. </span><span class="content">Introduction</span><a class="self-link" href="#intro"></a></h2>
   <p>The Application Binary Interface (ABI) in C++ is the architecture-specific protocol, including calling conventions and structure-layout rules, used on a system in order to support separate compilation of C++ code and the composition of programs from the output of those compilation tasks (often in the form of object files, static libraries, and/or shared libraries). In Prague, the committee considered the question of whether or not to take an "ABI break" for the C++23 revision of the standard. While the C++ specification does not specify an ABI, or ABI requirements, directly, our ability to evolve the standard requires consideration of ABI compatibility constraints imposed by the the design of existing shipping C++ ABIs. The results, unfortunately, were fairly inconclusive. A reasonable interpretation of the poll results is that the committee is willing to consider an ABI break at some point in the future, but not right now, and that while performance is an important objective of C++, stability is also important. Moreover, it is unclear exactly what change to facts on the ground would lead to a consensus shift in this regard. This proposal seeks to change the facts on the ground by providing additional language facilities to manage interface stability, including between different revisions of the standard, over time.</p>
   <p>Would adopting this proposal essentially imply an ABI break? Yes and no. It’s more complicated than that. By turning ABIs and interfaces into first-class facets of the language, code written may, by default, be ABI-incompaible with older C++ code. However, there’s an explicit and natural way to use this older code (i.e., to explicitly have access to, and provide new functionality following, the older ABI). This allows C++ programmers to manage ABI transitions and explicitly choose where and how to incur any associated performance penalties.</p>
   <p>Note that there is a lot of prior work in this general area, both in the generalized C/C++ ecosystem, and in other programming languages. See, for example, Swift’s module stability / library evolution model and Microsoft’s Component Object Model (COM).</p>
   <h2 class="heading settled" data-level="2" id="chlog"><span class="secno">2. </span><span class="content">Changelog</span><a class="self-link" href="#chlog"></a></h2>
   <ul>
    <li data-md>
     <p>r0: Initial version.</p>
   </ul>
   <h2 class="heading settled" data-level="3" id="impl"><span class="secno">3. </span><span class="content">Implementation</span><a class="self-link" href="#impl"></a></h2>
   <p>This proposal has not been implemented.</p>
   <h2 class="heading settled" data-level="4" id="what"><span class="secno">4. </span><span class="content">What Are We Talking About?</span><a class="self-link" href="#what"></a></h2>
   <p>Before we discuss how we might design language-level facilities to deal with ABI transitions, let’s discuss ABI constraints in more detail. The C++ specification does not specify an ABI, or ABI requirements, directly, but there are common implementation techniques that affect how we can evolve the specification, and the implementations themselves, while retaining the ability for a single implementation to serve both code compiled in the context of newer and older C++ standards.</p>
   <p>Many of these implementation techniques are designed around supporting C++'s separate-complication model: An application can be composed, at compile time, from multiple independently-compiled translation units. On many systems, in addition, an application can be composed, during program execution, from multiple independently-compiled translation units linked in the form of shared libraries. Some of these shared libraries are loaded during application startup, and sometimes, the application specifically directs the loading of additional shared libraries serving as "plugins" or similar.</p>
   <p>C++ allows some kinds of entities to be defined in multiple translation units in a program so long as their definitions are the same. This leads to our well-known One-Definition Rule (ODR). At an implementation level, to support separate compilation, this means that the implementations of these inline-linkage entities are often emitted multiple times (e.g., into multiple object files, shared libraries) and the linker and/or dynamic loader somehow picks one of these implementation instances to use for a particular program execution. For a conforming program, none of this should be visible. It’s important to note that we’re not just talking about entities that have an explicit manifestation in the C++ language, but also things, such as virtual-function tables, that are implicitly defined by the C++ code.</p>
   <p>In practice, ABIs are composed from different architecture/system-specified pieces, including:</p>
   <ul>
    <li data-md>
     <p>The C ABI: structure layouts, calling conventions, TLS implementation details, and so on. Might only apply to extern "C" entities, but is often used for many C++ entities as well.</p>
    <li data-md>
     <p>C++ name-mangling rules (i.e., how to encode the overload-identifying name of a function as a symbol name).</p>
    <li data-md>
     <p>The representation of C++ primitives (e.g., member pointers).</p>
    <li data-md>
     <p>The layout of aggregates that don’t have direct C analogues (e.g., have base classes, virtual functions).</p>
    <li data-md>
     <p>The layout of virtual-function tables, RTTI information, and other implementation-internal metadata.</p>
    <li data-md>
     <p>The method used to implement exception handling.</p>
   </ul>
   <p>When discussing this issue, we sometimes end up discussing both:</p>
   <ul>
    <li data-md>
     <p>The possibility of changing existing types in a way that is ABI-incompatible with existing implementations of those types.</p>
    <li data-md>
     <p>The possibility of changing/extending the ABI itself in order to improve functionality.</p>
   </ul>
   <p>What kinds of changes to a type are ABI-incompatible in this sense? These include:</p>
   <ul>
    <li data-md>
     <p>Changing the size of the type, the layout of the type (e.g., the order of the members, alignment, adding <code class="highlight"><c- p>[[</c-><c- n>no_unique_address</c-><c- p>]]</c-></code>, modifying base classes, adding the first virtual function).</p>
    <li data-md>
     <p>Changing the size or contents of the virtual-function table (e.g., changing the order in which virtual functions are defined, adding a new virtual function).</p>
    <li data-md>
     <p>Changing the return type of a function.</p>
   </ul>
   <p>There are some ABI-changing modifications one might make to a class that are not necessarily ABI incompatible, such as changing the type of a function, because an implementation might use the "provide both the new and old symbol" technique to simultaneously serve both old and new clients.</p>
   <p>It is also, of course, possible to make incompatible API (i.e., source-level) changes to a type. For example, adding new function overloads, removing a function, and so on.</p>
   <p>Changes to the ABI itself, such as changing the calling convention (e.g., how many registers are used for parameter passing, which register holds the <code class="highlight"><c- k>this</c-></code> pointer), are also part of the conversation around ABI changes and might be something a facility for dealing with ABI changes wishes to address.</p>
   <p>It is also important to be clear about whether we intend only to allow different, ABI-incompatible types of the same name to exist in the same program, which is currently often impossible because of inline-linkage definitions and other shared data (e.g., virtual-function tables), or whether we intend to allow for some translation unit to use both of these types simultaneously. It has been suggested that we need to only handle the former case and not the latter. While this may be a helpful step in the right direction, it is not clearly sufficient because this restricts us to a programming model where different parts of the application must use "C" interfaces to communicate across ABI boundaries, including using "C" types to marshal all data across these boundaries (instead of using the C++ types directly).</p>
   <h2 class="heading settled" data-level="5" id="whatnot"><span class="secno">5. </span><span class="content">What Are We Not Talking About?</span><a class="self-link" href="#whatnot"></a></h2>
   <p>We are not talking about changes to the semantics of existing types. If we want to make an existing function do something different, refrain from doing something, or do something more, with respect to other existing functions or public data members, this kind of ABI-change-handling facility may not help us. These are not ABI changes, but changes in semantics, and semantics changes should often change the names of types regardless of any other considerations.</p>
   <p>Thus, while a proposal to handle ABI changes can potentially deal with some kinds of API-level changes, such as removing a function, it cannot, in general, deal with associated semantic changes, such as the ability for the type to correctly implement the removed function.</p>
   <h2 class="heading settled" data-level="6" id="costs"><span class="secno">6. </span><span class="content">On Costs</span><a class="self-link" href="#costs"></a></h2>
   <p>Dealing with multiple implementations of library types nearly always imposes some kind of cost. Language-level facilities in this space may, and likely should, provide the programmer with a way to incur / trade off these costs in a way that makes sense for each particular application. A programmer might trade off the costs of:</p>
   <ul>
    <li data-md>
     <p>Indirection (i.e., performance overhead associated with dynamically-resolved abstraction)</p>
    <li data-md>
     <p>Specialization (i.e., overheads associated with generating multiple specializatons)</p>
    <li data-md>
     <p>Copying (i.e., the overheads associated with explicitly transitioning between data structures by copying data between one and the other)</p>
    <li data-md>
     <p>Technical dept (i.e., only using older types in the application, thus preventing the use of newer features)</p>
    <li data-md>
     <p>Ecosystem isolation (i.e., only using the newest types, perhaps preventing integration with other libraries and services)</p>
   </ul>
   <h2 class="heading settled" data-level="7" id="paste"><span class="secno">7. </span><span class="content">Some Past Experience</span><a class="self-link" href="#paste"></a></h2>
   <p>Some C++ standard-library implementations, such as libc++, use C++ inline namespaces and these may succeed at providing a partial strategy for dealing with ABI/API transitions. <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>vector</c-></code> is really <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>__1</c-><c- o>::</c-><c- n>vector</c-></code>, and so on. With all of the usual caveats about return types not being part of the name mangling on some systems, this can provide unique symbol names when using types from different (inline) namespaces. However:</p>
   <ul>
    <li data-md>
     <p>The inline namespace technique is not viral: it affects only direct uses of the standard-library types. User types that use standard-library types are not automatically tied to the same versioning scheme, and so, the inline namespace technique does not help user-defined types in the same way.</p>
    <li data-md>
     <p>On some systems, it doesn’t even help standard-library types if they’re used only as return types.</p>
    <li data-md>
     <p>It’s not clear how we might use this technique to manage ABI transitions directly.</p>
   </ul>
   <p>On this last point, it is important to consider another relevant experience that we have with type aliases (e.g., intmax_t). One straightforward suggestion for managing API transitions is to use a new namespace for each revision of the standard. This may work, but leads to a proliferation of vocabulary types (i.e., if std2 would be bad, this would be std2 and std3 and std4 and so on). A natural suggestion is to allow some of the types from the newer namespaces to be aliases for the types in the older namespaces. However, if this aliasing is implementation defined, or unspecified, it’s very difficult to create complete, unambiguous overload sets covering all of these types:</p>
<pre class="highlight"><c- b>void</c-> <c- nf>foo</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>&amp;</c-><c- n>x</c-><c- p>);</c->

<c- c1>// Is this needed or ambiguous with the definition above?</c->
<c- b>void</c-> <c- nf>foo</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>&amp;</c-><c- n>x</c-><c- p>);</c->
</pre>
   <p>So for this to work well, we need some adjusted set of rules for overload resolution.</p>
   <p>An alternative technique, used by GCC to help manage the C++11 std::string transition, is to introduce "viral" ABI tags. The idea is that these tags affect the mangling, but also affect the mangling of types that use the tagged types. It’s unclear what should happen if multiple tags are used, but for a single possible tag the high-level description of the behavior seems reasonably simple:</p>
<pre class="highlight"><c- n>From</c-> <c- n>the</c-> <c- n>GCC</c-> <c- nl>manual</c-><c- p>:</c->

<c- n>abi_tag</c-> <c- p>(</c-><c- s>"tag"</c-><c- p>,</c-> <c- p>...)</c->

<c- n>The</c-> <c- n>abi_tag</c-> <c- n>attribute</c-> <c- n>can</c-> <c- n>be</c-> <c- n>applied</c-> <c- n>to</c-> <c- n>a</c-> <c- n>function</c-><c- p>,</c-> <c- n>variable</c-><c- p>,</c-> <c- n>or</c-> <c- k>class</c->
<c- nc>declaration</c-><c- p>.</c-> <c- n>It</c-> <c- n>modifies</c-> <c- n>the</c-> <c- n>mangled</c-> <c- n>name</c-> <c- n>of</c-> <c- n>the</c-> <c- n>entity</c-> <c- n>to</c-> <c- n>incorporate</c-> <c- n>the</c-> <c- n>tag</c->
<c- n>name</c-><c- p>,</c-> <c- n>in</c-> <c- n>order</c-> <c- n>to</c-> <c- n>distinguish</c-> <c- n>the</c-> <c- n>function</c-> <c- n>or</c-> <c- k>class</c-> <c- nc>from</c-> <c- n>an</c-> <c- n>earlier</c-> <c- n>version</c->
<c- n>with</c-> <c- n>a</c-> <c- n>different</c-> <c- n>ABI</c-><c- p>;</c-> <c- n>perhaps</c-> <c- n>the</c-> <c- k>class</c-> <c- nc>has</c-> <c- n>changed</c-> <c- n>size</c-><c- p>,</c-> <c- n>or</c-> <c- n>the</c-> <c- n>function</c-> <c- n>has</c-> <c- n>a</c->
<c- n>different</c-> <c- k>return</c-> <c- n>type</c-> <c- n>that</c-> <c- n>is</c-> <c- n>not</c-> <c- n>encoded</c-> <c- n>in</c-> <c- n>the</c-> <c- n>mangled</c-> <c- n>name</c-><c- p>.</c->

<c- n>The</c-> <c- n>attribute</c-> <c- n>can</c-> <c- n>also</c-> <c- n>be</c-> <c- n>applied</c-> <c- n>to</c-> <c- n>an</c-> <c- kr>inline</c-> <c- k>namespace</c-><c- p>,</c-> <c- n>but</c-> <c- n>does</c-> <c- n>not</c-> <c- n>affect</c->
<c- n>the</c-> <c- n>mangled</c-> <c- n>name</c-> <c- n>of</c-> <c- n>the</c-> <c- k>namespace</c-><c- p>;</c-> <c- n>in</c-> <c- k>this</c-> <c- k>case</c-> <c- n>it</c-> <c- n>is</c-> <c- n>only</c-> <c- n>used</c-> <c- k>for</c-> <c- o>-</c-><c- n>Wabi</c-><c- o>-</c-><c- n>tag</c->
<c- n>warnings</c-> <c- n>and</c-> <c- n>automatic</c-> <c- n>tagging</c-> <c- n>of</c-> <c- n>functions</c-> <c- n>and</c-> <c- n>variables</c-><c- p>.</c-> <c- n>Tagging</c-> <c- kr>inline</c->
<c- n>namespaces</c-> <c- n>is</c-> <c- n>generally</c-> <c- n>preferable</c-> <c- n>to</c-> <c- n>tagging</c-> <c- n>individual</c-> <c- n>declarations</c-><c- p>,</c-> <c- n>but</c-> <c- n>the</c->
<c- n>latter</c-> <c- n>is</c-> <c- n>sometimes</c-> <c- n>necessary</c-><c- p>,</c-> <c- n>such</c-> <c- n>as</c-> <c- n>when</c-> <c- n>only</c-> <c- n>certain</c-> <c- n>members</c-> <c- n>of</c-> <c- n>a</c-> <c- k>class</c->
<c- nc>need</c-> <c- n>to</c-> <c- n>be</c-> <c- n>tagged</c-><c- p>.</c->

<c- n>The</c-> <c- n>argument</c-> <c- n>can</c-> <c- n>be</c-> <c- n>a</c-> <c- n>list</c-> <c- n>of</c-> <c- n>strings</c-> <c- n>of</c-> <c- n>arbitrary</c-> <c- n>length</c-><c- p>.</c-> <c- n>The</c-> <c- n>strings</c-> <c- n>are</c->
<c- n>sorted</c-> <c- n>on</c-> <c- n>output</c-><c- p>,</c-> <c- n>so</c-> <c- n>the</c-> <c- n>order</c-> <c- n>of</c-> <c- n>the</c-> <c- n>list</c-> <c- n>is</c-> <c- n>unimportant</c-><c- p>.</c->

<c- n>A</c-> <c- n>redeclaration</c-> <c- n>of</c-> <c- n>an</c-> <c- n>entity</c-> <c- n>must</c-> <c- n>not</c-> <c- n>add</c-> <c- k>new</c-> <c- n>ABI</c-> <c- n>tags</c-><c- p>,</c-> <c- n>since</c-> <c- n>doing</c-> <c- n>so</c-> <c- n>would</c->
<c- n>change</c-> <c- n>the</c-> <c- n>mangled</c-> <c- n>name</c-><c- p>.</c->

<c- n>The</c-> <c- n>ABI</c-> <c- n>tags</c-> <c- n>apply</c-> <c- n>to</c-> <c- n>a</c-> <c- n>name</c-><c- p>,</c-> <c- n>so</c-> <c- n>all</c-> <c- n>instantiations</c-> <c- n>and</c-> <c- n>specializations</c-> <c- n>of</c-> <c- n>a</c->
<c- k>template</c-> <c- n>have</c-> <c- n>the</c-> <c- n>same</c-> <c- n>tags</c-><c- p>.</c-> <c- n>The</c-> <c- n>attribute</c-> <c- n>will</c-> <c- n>be</c-> <c- n>ignored</c-> <c- k>if</c-> <c- n>applied</c-> <c- n>to</c-> <c- n>an</c->
<c- k>explicit</c-> <c- n>specialization</c-> <c- n>or</c-> <c- n>instantiation</c-><c- p>.</c->

<c- n>The</c-> <c- o>-</c-><c- n>Wabi</c-><c- o>-</c-><c- n>tag</c-> <c- n>flag</c-> <c- n>enables</c-> <c- n>a</c-> <c- n>warning</c-> <c- n>about</c-> <c- n>a</c-> <c- k>class</c-> <c- nc>which</c-> <c- n>does</c-> <c- n>not</c-> <c- n>have</c-> <c- n>all</c-> <c- n>the</c->
<c- n>ABI</c-> <c- n>tags</c-> <c- n>used</c-> <c- n>by</c-> <c- n>its</c-> <c- n>subobjects</c-> <c- n>and</c-> <c- k>virtual</c-> <c- n>functions</c-><c- p>;</c-> <c- k>for</c-> <c- n>users</c-> <c- n>with</c-> <c- n>code</c-> <c- n>that</c->
<c- n>needs</c-> <c- n>to</c-> <c- n>coexist</c-> <c- n>with</c-> <c- n>an</c-> <c- n>earlier</c-> <c- n>ABI</c-><c- p>,</c-> <c- k>using</c-> <c- k>this</c-> <c- n>option</c-> <c- n>can</c-> <c- n>help</c-> <c- n>to</c-> <c- n>find</c-> <c- n>all</c->
<c- n>affected</c-> <c- n>types</c-> <c- n>that</c-> <c- n>need</c-> <c- n>to</c-> <c- n>be</c-> <c- n>tagged</c-><c- p>.</c->

<c- n>When</c-> <c- n>a</c-> <c- n>type</c-> <c- n>involving</c-> <c- n>an</c-> <c- n>ABI</c-> <c- n>tag</c-> <c- n>is</c-> <c- n>used</c-> <c- n>as</c-> <c- n>the</c-> <c- n>type</c-> <c- n>of</c-> <c- n>a</c-> <c- n>variable</c-> <c- n>or</c-> <c- k>return</c->
<c- n>type</c-> <c- n>of</c-> <c- n>a</c-> <c- n>function</c-> <c- n>where</c-> <c- n>that</c-> <c- n>tag</c-> <c- n>is</c-> <c- n>not</c-> <c- n>already</c-> <c- n>present</c-> <c- n>in</c-> <c- n>the</c-> <c- n>signature</c-> <c- n>of</c->
<c- n>the</c-> <c- n>function</c-><c- p>,</c-> <c- n>the</c-> <c- n>tag</c-> <c- n>is</c-> <c- n>automatically</c-> <c- n>applied</c-> <c- n>to</c-> <c- n>the</c-> <c- n>variable</c-> <c- n>or</c-> <c- n>function</c-><c- p>.</c->
<c- o>-</c-><c- n>Wabi</c-><c- o>-</c-><c- n>tag</c-> <c- n>also</c-> <c- n>warns</c-> <c- n>about</c-> <c- k>this</c-> <c- n>situation</c-><c- p>;</c-> <c- k>this</c-> <c- n>warning</c-> <c- n>can</c-> <c- n>be</c-> <c- n>avoided</c-> <c- n>by</c->
<c- n>explicitly</c-> <c- n>tagging</c-> <c- n>the</c-> <c- n>variable</c-> <c- n>or</c-> <c- n>function</c-> <c- n>or</c-> <c- n>moving</c-> <c- n>it</c-> <c- n>into</c-> <c- n>a</c-> <c- n>tagged</c-> <c- kr>inline</c->
<c- k>namespace</c-><c- p>.</c->
</pre>
   <p>A couple of notes: First, care is required that forward-declared types are properly annotated:</p>
<pre class="highlight"><c- k>struct</c-> <c- n>A</c-><c- p>;</c->

<c- c1>// We need to mangle the name of A here into the name of the function, so we</c->
<c- c1>// need to know if it has an ABI tag now.</c->
<c- b>void</c-> <c- nf>f</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>unique_ptr</c-><c- o>&lt;</c-><c- n>A</c-><c- o>></c-><c- p>);</c->
</pre>
   <p>Second, to maintain ODR-provided invariants, we may also need to tag inline-linkage entities based everything used in their definitions, not just those types that appear on the interface. In this example (provided by Richard Smith):</p>
<pre class="highlight"><c- kr>inline</c-> <c- k>const</c-> <c- b>char</c-> <c- o>*</c-><c- nf>getThing</c-><c- p>()</c-> <c- p>{</c->
  <c- k>static</c-> <c- n>std</c-><c- o>::</c-><c- n>string</c-> <c- n>thing</c-> <c- o>=</c-> <c- n>getenv</c-><c- p>(</c-><c- s>"thing"</c-><c- p>);</c->
  <c- k>return</c-> <c- n>thing</c-><c- p>.</c-><c- n>c_str</c-><c- p>();</c->
<c- p>}</c->
</pre>
   <p>even if we mangle the name of the static variable using the ABI identifier, it’s true that the C++23-compiled getThing will return a different pointer than the C++20-compiled getThing (and, if we don’t always select a consistent implementation of the function matching the language mode of the caller, a different pointer might be returned depending on whether or not any particular call is inlined).</p>
   <p>This tag-based mechanism does not address the problem of allowing the user to name both types in the same translation unit.</p>
   <h2 class="heading settled" data-level="8" id="jrc"><span class="secno">8. </span><span class="content">Just Recompile!</span><a class="self-link" href="#jrc"></a></h2>
   <p>We note that some users of C++ can simply recompile all of their code as desired, and thus, these kinds of ABI considerations are not relevant to them. Not all users can, however. Some users can recompile their code as desired, but depend on system libraries and/or system interfaces provided only using some older ABI (e.g. the BeOS API, which is native C++, was like this). Some users can recompile their code but depend on third-party libraries that they cannot recompile. Some users can recompile their code, but their code is a plugin to a third-party application with a fixed ABI. Some users can recompile their code, but their code must load plugins that use the older ABI. Some users can recompile their code, but doing so along with a language-version upgrade is a slow, expensive process if it must happen synchronously across the entire organization.</p>
   <p>In short, many users can recompile their code. If they couldn’t, they don’t care about using the latest C++ features. However, adoption will be increased if users can recompile their code to use the latest C++ without requiring the same for all transitive dependencies.</p>
   <h2 class="heading settled" data-level="9" id="helpw"><span class="secno">9. </span><span class="content">Does This Help With ...</span><a class="self-link" href="#helpw"></a></h2>
   <p>People have asked whether this proposal would help with some specific use cases that people have had in mind, including:</p>
   <ul>
    <li data-md>
     <p>std::regex</p>
   </ul>
   <p>Whether or not this might help with std::regex depends greatly on how we might want to change the specification and/or implementations. Presumably, we would want a better (more efficient) way to handle localized character classification, better algorithms and automata optimizations, and so on. We might also need to significantly change the interface to accomplish these goals, however, in which case none of this is particularly relevant (because we’ll need to change much of the code using the class regardless and/or just name the new version something else). However, if we restrict this problem to looking only at the problem of updating the algorithms in inline-linkage functions, and potentially, data-structure changes that can be made in a purely-additive way, then yes, this proposal should help that kind of transition.</p>
   <ul>
    <li data-md>
     <p>std::unordered_map</p>
   </ul>
   <p>This, again, is going to depend on what kinds of changes we desire to unordered_map. If we’re trying to allow more implementation freedom, for example, to allow for different kinds of open-addressing strategies, by loosening our iterator-stability guarantees, then that’s a semantic change that cannot necessarily be addressed by the proposed facility. If, on the other hand, we’re talking about something like changing an implementation from using power-of-two bucket counts to prime bucket counts (or Fibonacci or whatever), then the answer is: maybe. It depends on how deeply the current choice is embedded in the design of the current data structure. If the implementation works with any bucket sizes, it’s just that we want to change how the defaults are selected, then this will help. If we can’t provide a new implementation that will also work with inlined member functions of the old implementation, then this may not help.</p>
   <ul>
    <li data-md>
     <p>std::unique_ptr</p>
   </ul>
   <p>An interesting case because, if the primary desire is to effectively modify the calling convention to prevent passing a pointer to the pointer, this requires a kind of semantic change. For background, see CppCon 2019 talk by Chandler Carruth: "There Are No Zero-cost Abstractions". Because unique_ptr has a non-trivial destructor (and constructor) it is passed using the general convention for non-trivial aggregates, thus by pointer. This is inefficient for this kind of wrapper type but, for ABIs where the temporaries are constructed in the caller, ensures a unique value of the this pointer in the constructor and destructor. We could change this, but that would require making a new kind of object (maybe by leveraging our <code class="highlight"><c- p>[[</c-><c- n>no_unique_address</c-><c- p>]]</c-></code> attribute in a new way). In any case, this proposed facility would help with this transition, as would any facility allowing the implementation to give a new mangling scheme to the unique_ptr with these new semantics.</p>
   <h2 class="heading settled" data-level="10" id="req"><span class="secno">10. </span><span class="content">Requirements</span><a class="self-link" href="#req"></a></h2>
   <p>Some requirements for a facility to help ABI transitions:</p>
   <ol>
    <li data-md>
     <p>C++ must default to providing flexibility over interface stability. If the programmer does nothing explicit, then they should get the highest possible performance (relative to that provided by other aspects of this proposal). This includes uses of standard-library types and functions.</p>
    <li data-md>
     <p>C++ must provide a way for types to provide interfaces that prioritize stability over flexibility. This must allow code written using a newer version of C++ to call functions in code written in an ABI-incompatible older version of C++, and code written in an older version of C++ to call functions in code written in an ABI-incompatible newer version of C++. It must be possible to implement this feature such that the ABI of pre-C++-23 code can be selected as required.</p>
    <li data-md>
     <p>This facility must be generalized, and not specific to different C++ versions. We recognize that the C++ standard library is not the only library with ABI concerns.</p>
    <li data-md>
     <p>This facility should work naturally with modules and should strive to not require viral annotations while retaining the ability to make expensive operations explicitly visible to readers of the code.</p>
   </ol>
   <p>This proposal certainly introduces new concepts (colloquial) into the C++ language, but aims to do so in a way that integrates naturally and provides behaviors akin to existing aspects of C++ functionality. It does this by:</p>
   <ol>
    <li data-md>
     <p>Fully integrating into the type system. This allows existing features such as template specialization and overloading to provide a lot of the necessary semantics.</p>
    <li data-md>
     <p>Fully integrating into C++'s name-lookup paradigm, thus making it easier to reason about how names work.</p>
   </ol>
   <p>In addition, we recognize that we cannot predict the future, but we can require certain knowledge of the past, and so it must be the responsibility of new code to provide interfaces compatible with older users (and not the other way around).</p>
   <p>It’s also important to consider the kinds of changes that the stable interfaces should be resilient against because this has an effect on how the implementation is designed. Some questions are:</p>
   <ol>
    <li data-md>
     <p>Does stability imply a lack of inlining? Note that there is a potential separation here between inline linkage and actually allowing compiler inlining. Allowing inlining potentially requires "virtual" data-member access (i.e., making the set of internal data members used by these inline functions part of the abstract, stable interface).</p>
    <li data-md>
     <p>Does stability imply only additive changes? Adding new functions to the interface? Adding new data members? How about changing the type of existing members? Type changes that change the size vs. type changes that don’t change the size? Replacing a data member with a function of other data members?</p>
   </ol>
   <h2 class="heading settled" data-level="11" id="diffex"><span class="secno">11. </span><span class="content">Differences From Existing Features</span><a class="self-link" href="#diffex"></a></h2>
   <p>Upon reading this proposal, you might object that what is being proposed here seems similar to a number of features that we already have in C++. We already have virtual functions, inline namespaces, and so on. Moreover, many of these features are used in practice specifically to support some of the use cases discussed here. Why do we need something new?</p>
   <p>Let’s try to imagine the best that we could do with existing features if we wanted to update the standard library in a somewhat analogous way to what is effectively proposed here. First, like libc++ does, we would put all standard-library classes into an inline namespace. For future C++ revisions, implementations would make the namespace containing the previous implementation non-inline, and create a new inline namespace for the new versions of the standard library. This would enable simultaneous access to both the old and new standard library within the same application; technically speaking, changing the namespace definitions like this is an ODR violation, but a benign one in practice, and we could also make this okay with some kind of explicit wording. However, that doesn’t address the problem of being able to write code that uses standard-library types on public library interfaces and have it be resilient to standard-library updates. In fact, if we just follow this inline-namespace approach, we’ve made the problem worse, by forcing all of these interfaces to explicitly traffic in C++-revision-specific standard-library types and, thus, add a lot of manual copying/conversion around all of this public-interface-using code.</p>
   <p>Our existing tool for addressing this next problem is to introduce a class hierarchy and make the public interface mostly, or entirely, virtual. If we had such a class hierarchy, we could use these types on public interfaces and, by doing so, gain resilience to functionality additions within the standard-library classes. However, we can’t do this for many of the standard-library classes themselves, such as containers, as this would have serious negative performance implications: any time we had a pointer or reference to any of these types, the compiler needs to assume that it might be dealing with some derived class, and none of the functions would be inlined. Moreover, C++ doesn’t have a way to say, "X is a pointer to some type T which has virtual functions, but I know the pointed-to object’s type is exactly T and not some derived type." This all implies that our class hierarchy with virtual functions must be a separate hierarchy of wrapper types: A wrapper type for each C++23 standard-library class, a derived wrapper type for each C++26 standard-library class, and so on, with essentially all-virtual interfaces mirroring those of the types wrapped by each.</p>
   <p>This has a few problems. First, when using the wrapper types, the fact that all of the functions are virtual means that essentially nothing is inlined, and this leads to suboptimal performance. Also, standard-library types have plenty of templated member functions, and these can’t be virtual regardless. In some sense, this implies a somewhat-better solution: Our class hierarchy of wrapper types become friends of the types they wrap, and the interface is the same as the wrapped class, except that virtual functions are used to access the type’s data members.</p>
   <p>So this leaves us with a library design that looks something like this:</p>
<pre class="highlight"><c- cp>#include</c-> &lt;utility>

<c- k>namespace</c-> <c- n>std</c-> <c- p>{</c->
<c- k>namespace</c-> <c- n>cxx20</c-> <c- p>{</c->

<c- k>namespace</c-> <c- n>interface</c-> <c- p>{</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing</c-><c- p>;</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing_wrapper</c-><c- p>;</c->

<c- p>}</c->

<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- k>class</c-> <c- nc>thing</c-> <c- p>{</c->
<c- k>protected</c-><c- o>:</c->
  <c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>,</c-> <c- n>z</c-><c- p>;</c->

  <c- k>friend</c-> <c- k>class</c-> <c- nc>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>;</c->

<c- k>public</c-><c- o>:</c->
  <c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>)</c->
    <c- o>:</c-> <c- n>x</c-><c- p>(</c-><c- n>x</c-><c- p>),</c-> <c- n>y</c-><c- p>(</c-><c- n>y</c-><c- p>),</c-> <c- n>z</c-><c- p>(</c-><c- n>z</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

  <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>x</c-> <c- o>+</c-> <c- n>y</c-> <c- o>+</c-> <c- n>z</c-><c- p>;</c->
  <c- p>}</c->
<c- p>};</c->

<c- k>namespace</c-> <c- n>interface</c-> <c- p>{</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing</c-> <c- p>{</c->
  <c- k>protected</c-><c- o>:</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->

  <c- k>public</c-><c- o>:</c->
    <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
      <c- k>return</c-> <c- n>get_x</c-><c- p>()</c-> <c- o>+</c-> <c- n>get_y</c-><c- p>()</c-> <c- o>+</c-> <c- n>get_z</c-><c- p>();</c->
    <c- p>}</c->

    <c- k>virtual</c-> <c- k>operator</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- k>virtual</c-> <c- k>operator</c-> <c- k>const</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- p>};</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing_wrapper</c-> <c- o>:</c-> <c- k>public</c-> <c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- p>{</c->
    <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- n>UO</c-><c- p>;</c-> <c- c1>// The underlying object.</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>x</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>x</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>y</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>y</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>z</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>z</c-><c- p>;</c-> <c- p>}</c->

  <c- k>public</c-><c- o>:</c->
    <c- n>thing_wrapper</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>)</c->
      <c- o>:</c-> <c- n>UO</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>,</c-> <c- n>z</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

    <c- n>thing_wrapper</c-><c- p>(</c-><c- k>const</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- n>O</c-><c- p>)</c-> <c- o>:</c-> <c- n>UO</c-><c- p>(</c-><c- n>O</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

    <c- n>thing_wrapper</c-><c- p>(</c-><c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c-><c- n>O</c-><c- p>)</c-> <c- o>:</c-> <c- n>UO</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>O</c-><c- p>))</c-> <c- p>{</c-> <c- p>}</c->

    <c- k>virtual</c-> <c- k>operator</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>;</c-> <c- p>}</c->
    <c- k>virtual</c-> <c- k>operator</c-> <c- k>const</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>;</c-> <c- p>}</c->
  <c- p>};</c->
<c- p>}</c->

<c- p>}</c-> <c- c1>// namespace cxx20</c->

<c- kr>inline</c-> <c- k>namespace</c-> <c- n>cxx23</c-> <c- p>{</c->

<c- k>namespace</c-> <c- n>interface</c-> <c- p>{</c->
  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing</c-><c- p>;</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing_wrapper</c-><c- p>;</c->
<c- p>}</c->

<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- k>class</c-> <c- nc>thing</c-> <c- p>{</c->
<c- k>protected</c-><c- o>:</c->
  <c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>,</c-> <c- n>z</c-><c- p>,</c-> <c- n>w</c-><c- p>;</c->

  <c- k>friend</c-> <c- k>class</c-> <c- nc>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>;</c->

<c- k>public</c-><c- o>:</c->
  <c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>w</c-> <c- o>=</c-> <c- n>T</c-><c- p>(</c-><c- mi>0</c-><c- p>))</c->
    <c- o>:</c-> <c- n>x</c-><c- p>(</c-><c- n>x</c-><c- p>),</c-> <c- n>y</c-><c- p>(</c-><c- n>y</c-><c- p>),</c-> <c- n>z</c-><c- p>(</c-><c- n>z</c-><c- p>),</c-> <c- n>w</c-><c- p>(</c-><c- n>w</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

  <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>x</c-> <c- o>+</c-> <c- n>y</c-> <c- o>+</c-> <c- n>z</c-> <c- o>+</c-> <c- n>w</c-><c- p>;</c->
  <c- p>}</c->
<c- p>};</c->

<c- k>namespace</c-> <c- n>interface</c-> <c- p>{</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing</c-> <c- o>:</c-> <c- k>public</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>interface</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- p>{</c->
  <c- k>protected</c-><c- o>:</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_w</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_w</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->

  <c- k>public</c-><c- o>:</c->
    <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
      <c- k>return</c-> <c- k>this</c-><c- o>-></c-><c- n>get_x</c-><c- p>()</c-> <c- o>+</c-> <c- k>this</c-><c- o>-></c-><c- n>get_y</c-><c- p>()</c-> <c- o>+</c-> <c- k>this</c-><c- o>-></c-><c- n>get_z</c-><c- p>()</c-> <c- o>+</c-> <c- n>get_w</c-><c- p>();</c->
    <c- p>}</c->

    <c- k>virtual</c-> <c- k>operator</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- k>virtual</c-> <c- k>operator</c-> <c- k>const</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- p>};</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing_wrapper</c-> <c- o>:</c-> <c- k>public</c-> <c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- p>{</c->
  <c- k>protected</c-><c- o>:</c->
    <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- n>UO</c-><c- p>;</c-> <c- c1>// The underlying object.</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>x</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>x</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>y</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>y</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>z</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>z</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_w</c-><c- p>()</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>w</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_w</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>.</c-><c- n>w</c-><c- p>;</c-> <c- p>}</c->

  <c- k>public</c-><c- o>:</c->
    <c- n>thing_wrapper</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>w</c-> <c- o>=</c-> <c- n>T</c-><c- p>(</c-><c- mi>0</c-><c- p>))</c->
      <c- o>:</c-> <c- n>UO</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>,</c-> <c- n>z</c-><c- p>,</c-> <c- n>w</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

    <c- n>thing_wrapper</c-><c- p>(</c-><c- k>const</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- n>O</c-><c- p>)</c-> <c- o>:</c-> <c- n>UO</c-><c- p>(</c-><c- n>O</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

    <c- n>thing_wrapper</c-><c- p>(</c-><c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;&amp;</c-><c- n>O</c-><c- p>)</c-> <c- o>:</c-> <c- n>UO</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>O</c-><c- p>))</c-> <c- p>{</c-> <c- p>}</c->

    <c- k>virtual</c-> <c- k>operator</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>;</c-> <c- p>}</c->
    <c- k>virtual</c-> <c- k>operator</c-> <c- k>const</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- p>;</c-> <c- p>}</c->
  <c- p>};</c->

<c- p>}</c->

<c- p>}</c-> <c- c1>// inline namespace cxx23</c->
<c- p>}</c-> <c- c1>// namespace std</c->
</pre>
   <p>Now you might object that some of the code duplication could be removed by using a CRTP approach and/or other refactoring, and that’s likely correct. You might also object that, even if we had the "object_lifetime_invariant_reference" attribute to tell the optimizer that the function always returned a reference to the same object, that still wouldn’t be optimal because it would be better to return object-lifetime-invariant object offsets instead, and that’s also likely correct. One way or another, however, the code pattern needed here is both heavy on boilerplate and, even with that, performance suboptimal compared to what a compiler might be able to generate for a language feature with similar semantics.</p>
   <p>Most importantly, however, there’s a design flaw in this library structure. Consider this function that someone may need to write:</p>
<pre class="highlight"><c- b>void</c-> <c- nf>resilient_abi</c-><c- p>(</c-><c- n>cxx20</c-><c- o>::</c-><c- n>interface</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>*</c-><c- p>);</c->

<c- b>void</c-> <c- nf>call_resilient_abi</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>*</c-><c- n>t</c-><c- p>)</c-> <c- p>{</c->
  <c- c1>// Assuming for simplicity that we know that t is not nullptr...</c->

  <c- c1>// Should we use the copy or the move constructor of thing_wrapper here?</c->
  <c- n>std</c-><c- o>::</c-><c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>*</c-><c- n>w</c-> <c- o>=</c-> <c- k>new</c-> <c- n>std</c-><c- o>::</c-><c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-><c- p>(</c-><c- o>*</c-><c- n>t</c-><c- p>);</c->
  <c- n>resilient_abi</c-><c- p>(</c-><c- n>w</c-><c- p>);</c->

  <c- c1>// Hrmm... should I delete w now? Should I delete t?</c->
<c- p>}</c->
</pre>
   <p>The problem here is that, if I’m wrapping an API that takes an object by pointer or reference, the relevant lifetime and ownership semantics of the pointer/reference parameters are unclear from the type system alone. The API usage here requires deep knowledge, and while in some sense this is okay (it is normally important to understand the behavior of the functions that you call), it also makes it more difficult to integrate use of these interfaces into large code bases. It’s not possible for tooling to wrap interfaces like this in a generic way. What we really want is some way to tie the lifetime of w to the lifetime of t (in the example above), and we don’t have any way to do that within this wrapper function.</p>
   <p>A solution to this problem is clear, but unfortunate in it’s own ways. We cannot make the underlying types unconditionally have the virtual functions because that would both unconditionally increase the object size (which breaks one of our requirements), and because it’s then not possible to provide both the member functions that use of the virtual data-member access and those that don’t (with the same names). An alternative is to create two different variants of each type, one normal one, and one also holds a wrapper object of itself. We can make an interface like this:</p>
<pre class="highlight"><c- k>namespace</c-> <c- n>std</c-> <c- p>{</c->
<c- k>namespace</c-> <c- n>cxx20</c-> <c- p>{</c->

<c- k>namespace</c-> <c- n>interface</c-> <c- p>{</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing</c-><c- p>;</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing_wrapper</c-><c- p>;</c->

<c- p>}</c->

<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- k>class</c-> <c- nc>thing_unwrappable</c-> <c- p>{</c->
<c- k>protected</c-><c- o>:</c->
  <c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>,</c-> <c- n>z</c-><c- p>;</c->

  <c- k>friend</c-> <c- k>class</c-> <c- nc>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>;</c->

<c- k>public</c-><c- o>:</c->
  <c- n>thing_unwrappable</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>)</c->
    <c- o>:</c-> <c- n>x</c-><c- p>(</c-><c- n>x</c-><c- p>),</c-> <c- n>y</c-><c- p>(</c-><c- n>y</c-><c- p>),</c-> <c- n>z</c-><c- p>(</c-><c- n>z</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

  <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>x</c-> <c- o>+</c-> <c- n>y</c-> <c- o>+</c-> <c- n>z</c-><c- p>;</c->
  <c- p>}</c->
<c- p>};</c->

<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- k>class</c-> <c- nc>thing</c-> <c- o>:</c-> <c- k>public</c-> <c- n>thing_unwrappable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- p>{</c->
<c- k>protected</c-><c- o>:</c->
  <c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>wpr</c-><c- p>;</c->

<c- k>public</c-><c- o>:</c->
  <c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>);</c->
  <c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>thing</c-> <c- o>&amp;</c-><c- n>P</c-><c- p>);</c->
  <c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>wrapper</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>wpr</c-><c- p>;</c-> <c- p>}</c->
  <c- o>~</c-><c- n>thing</c-><c- p>()</c-> <c- p>{</c-> <c- k>delete</c-> <c- n>wpr</c-><c- p>;</c-> <c- p>}</c->
<c- p>};</c->

<c- k>namespace</c-> <c- n>interface</c-> <c- p>{</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing</c-> <c- p>{</c->
  <c- k>protected</c-><c- o>:</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->

  <c- k>public</c-><c- o>:</c->
    <c- k>virtual</c-> <c- o>~</c-><c- n>thing</c-><c- p>()</c-> <c- p>{</c-> <c- p>}</c->

    <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
      <c- k>return</c-> <c- n>get_x</c-><c- p>()</c-> <c- o>+</c-> <c- n>get_y</c-><c- p>()</c-> <c- o>+</c-> <c- n>get_z</c-><c- p>();</c->
    <c- p>}</c->

    <c- k>virtual</c-> <c- k>operator</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- k>virtual</c-> <c- k>operator</c-> <c- k>const</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- p>};</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing_wrapper</c-> <c- o>:</c-> <c- k>public</c-> <c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- p>{</c->
    <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>UO</c-><c- p>;</c-> <c- c1>// The underlying object.</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>x</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>x</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>y</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>y</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>z</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>z</c-><c- p>;</c-> <c- p>}</c->

  <c- k>public</c-><c- o>:</c->
    <c- o>~</c-><c- n>thing_wrapper</c-><c- p>()</c-> <c- p>{</c->
      <c- k>if</c-> <c- p>(</c-><c- n>UO</c-><c- p>)</c-> <c- p>{</c->
        <c- n>UO</c-><c- o>-></c-><c- n>release_wrapper</c-><c- p>();</c->
        <c- k>delete</c-> <c- n>UO</c-><c- p>;</c->
      <c- p>}</c->
    <c- p>}</c->

    <c- n>thing_wrapper</c-><c- p>(</c-><c- k>const</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>O</c-><c- p>)</c-> <c- o>:</c-> <c- n>UO</c-><c- p>(</c-><c- n>O</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

    <c- k>virtual</c-> <c- k>operator</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- o>*</c-><c- n>UO</c-><c- p>;</c-> <c- p>}</c->
    <c- k>virtual</c-> <c- k>operator</c-> <c- k>const</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- o>*</c-><c- n>UO</c-><c- p>;</c-> <c- p>}</c->
  <c- p>};</c->
<c- p>}</c-> <c- c1>// namespace interface</c->

<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>)</c->
    <c- o>:</c-> <c- n>thing_unwrappable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>,</c-> <c- n>z</c-><c- p>),</c->
      <c- n>wpr</c-><c- p>(</c-><c- k>new</c-> <c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>(</c-><c- k>this</c-><c- p>))</c-> <c- p>{</c-> <c- p>}</c->
<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>thing</c-> <c- o>&amp;</c-><c- n>P</c-><c- p>)</c->
  <c- o>:</c-> <c- n>thing_unwrappable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>(</c-><c- n>P</c-><c- p>),</c->
    <c- n>wpr</c-><c- p>(</c-><c- k>new</c-> <c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>(</c-><c- k>this</c-><c- p>))</c-> <c- p>{</c-> <c- p>}</c->

<c- p>}</c-> <c- c1>// namespace cxx20</c->

<c- kr>inline</c-> <c- k>namespace</c-> <c- n>cxx23</c-> <c- p>{</c->

<c- k>namespace</c-> <c- n>interface</c-> <c- p>{</c->
  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing</c-><c- p>;</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing_wrapper</c-><c- p>;</c->
<c- p>}</c->

<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- k>class</c-> <c- nc>thing_unwrappable</c-> <c- p>{</c->
<c- k>protected</c-><c- o>:</c->
  <c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>,</c-> <c- n>z</c-><c- p>,</c-> <c- n>w</c-><c- p>;</c->

  <c- k>friend</c-> <c- k>class</c-> <c- nc>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>;</c->

<c- k>public</c-><c- o>:</c->
  <c- n>thing_unwrappable</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>w</c-> <c- o>=</c-> <c- n>T</c-><c- p>(</c-><c- mi>0</c-><c- p>))</c->
    <c- o>:</c-> <c- n>x</c-><c- p>(</c-><c- n>x</c-><c- p>),</c-> <c- n>y</c-><c- p>(</c-><c- n>y</c-><c- p>),</c-> <c- n>z</c-><c- p>(</c-><c- n>z</c-><c- p>),</c-> <c- n>w</c-><c- p>(</c-><c- n>w</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

  <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>x</c-> <c- o>+</c-> <c- n>y</c-> <c- o>+</c-> <c- n>z</c-> <c- o>+</c-> <c- n>w</c-><c- p>;</c->
  <c- p>}</c->
<c- p>};</c->

<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- k>class</c-> <c- nc>thing</c-> <c- o>:</c-> <c- k>public</c-> <c- n>thing_unwrappable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- p>{</c->
<c- k>protected</c-><c- o>:</c->
  <c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>wpr</c-><c- p>;</c->

<c- k>public</c-><c- o>:</c->
  <c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>w</c-> <c- o>=</c-> <c- n>T</c-><c- p>(</c-><c- mi>0</c-><c- p>));</c->
  <c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>thing</c-> <c- o>&amp;</c-><c- n>P</c-><c- p>);</c->
  <c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>wrapper</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>wpr</c-><c- p>;</c-> <c- p>}</c->
  <c- o>~</c-><c- n>thing</c-><c- p>()</c-> <c- p>{</c-> <c- k>delete</c-> <c- n>wpr</c-><c- p>;</c-> <c- p>}</c->
<c- p>};</c->

<c- k>namespace</c-> <c- n>interface</c-> <c- p>{</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing</c-> <c- o>:</c-> <c- k>public</c-> <c- n>cxx20</c-><c- o>::</c-><c- n>interface</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- p>{</c->
  <c- k>protected</c-><c- o>:</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_w</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_w</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->

  <c- k>public</c-><c- o>:</c->
    <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
      <c- k>return</c-> <c- k>this</c-><c- o>-></c-><c- n>get_x</c-><c- p>()</c-> <c- o>+</c-> <c- k>this</c-><c- o>-></c-><c- n>get_y</c-><c- p>()</c-> <c- o>+</c-> <c- k>this</c-><c- o>-></c-><c- n>get_z</c-><c- p>()</c-> <c- o>+</c-> <c- n>get_w</c-><c- p>();</c->
    <c- p>}</c->

    <c- k>virtual</c-> <c- k>operator</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- k>virtual</c-> <c- k>operator</c-> <c- k>const</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>const</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
  <c- p>};</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>thing_wrapper</c-> <c- o>:</c-> <c- k>public</c-> <c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- p>{</c->
  <c- k>protected</c-><c- o>:</c->
    <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- n>UO</c-><c- p>;</c-> <c- c1>// The underlying object.</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>x</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_x</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>x</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>y</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_y</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>y</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>z</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_z</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>z</c-><c- p>;</c-> <c- p>}</c->

    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_w</c-><c- p>()</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>w</c-><c- p>;</c-> <c- p>}</c->
    <c- d>/*[[object_lifetime_invariant_reference]]*/</c->
    <c- k>virtual</c-> <c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>get_w</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- n>UO</c-><c- o>-></c-><c- n>w</c-><c- p>;</c-> <c- p>}</c->

  <c- k>public</c-><c- o>:</c->
    <c- o>~</c-><c- n>thing_wrapper</c-><c- p>()</c-> <c- p>{</c->
      <c- k>if</c-> <c- p>(</c-><c- n>UO</c-><c- p>)</c-> <c- p>{</c->
        <c- n>UO</c-><c- o>-></c-><c- n>release_wrapper</c-><c- p>();</c->
        <c- k>delete</c-> <c- n>UO</c-><c- p>;</c->
      <c- p>}</c->
    <c- p>}</c->

    <c- n>thing_wrapper</c-><c- p>(</c-><c- k>const</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>*</c-><c- n>O</c-><c- p>)</c-> <c- o>:</c-> <c- n>UO</c-><c- p>(</c-><c- n>O</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

    <c- k>virtual</c-> <c- k>operator</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- o>*</c-><c- n>UO</c-><c- p>;</c-> <c- p>}</c->
    <c- k>virtual</c-> <c- k>operator</c-> <c- k>const</c-> <c- n>cxx23</c-><c- o>::</c-><c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- o>&amp;</c-><c- p>()</c-> <c- k>const</c-> <c- k>override</c-> <c- p>{</c-> <c- k>return</c-> <c- o>*</c-><c- n>UO</c-><c- p>;</c-> <c- p>}</c->
  <c- p>};</c->

<c- p>}</c-> <c- c1>// namespace interface</c->

<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>w</c-><c- p>)</c->
    <c- o>:</c-> <c- n>thing_unwrappable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>,</c-> <c- n>z</c-><c- p>,</c-> <c- n>w</c-><c- p>),</c->
      <c- n>wpr</c-><c- p>(</c-><c- k>new</c-> <c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>(</c-><c- k>this</c-><c- p>))</c-> <c- p>{</c-> <c- p>}</c->
<c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- n>thing</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>thing</c-><c- p>(</c-><c- k>const</c-> <c- n>thing</c-> <c- o>&amp;</c-><c- n>P</c-><c- p>)</c->
  <c- o>:</c-> <c- n>thing_unwrappable</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>(</c-><c- n>P</c-><c- p>),</c->
    <c- n>wpr</c-><c- p>(</c-><c- k>new</c-> <c- n>interface</c-><c- o>::</c-><c- n>thing_wrapper</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>(</c-><c- k>this</c-><c- p>))</c-> <c- p>{</c-> <c- p>}</c->

<c- p>}</c-> <c- c1>// inline namespace cxx23</c->
<c- p>}</c-> <c- c1>// namespace std</c->
</pre>
   <p>And, now, the user can choose std::thing, or std::thing_unwrappable, depending on whether or not the user wants to use the type with the ABI-resilient interfaces (which use the wrapper types). The public library interfaces across which we need to be resilient to ABI changes, we can use the wrapper types. The lifetime of the wrapper object is now tied to that of the underlying object. However, because we need to be able to use the delete operator with the wrappers and have that delete the underlying object (and also delete the underlying object and have it delete the wrapper), we’re stuck needing two independent objects with dynamic allocation and pointers that would not be necessary if the wrapper were a proper subobject of the object being wrapped.</p>
   <p>To goal of this proposal is to give us the benefit of this kind of library structure, but without needing separate object allocations, and without the boilerplate and related usage complexity.</p>
   <p>As a language feature, we also have more freedom to provide transparent proxies via the creation of "fat pointers" (i.e., the feature can be implemented by bundling (a pointer to) the metadata associated with the interface abstraction with the pointer to the object itself). This allows the wrapped objects to suffer from no additional size (i.e., no vtable-like pointer needs to be stored in each object). At the time when an unresolved interface pointer is assigned, either the source is another such pointer, in which case the metadata can be copied, or we know the concrete type of the object and the compiler can cause the correct metadata to be stored.</p>
   <p>With this proposal, the above library type looks like this:</p>
<pre class="highlight"><c- k>namespace</c-> <c- n>std</c-> <c- p>{</c->
  <c- n>interface</c-> <c- n>cxx20</c-><c- p>;</c->
  <c- n>interface</c-> <c- nl>cxx23</c-> <c- p>:</c-> <c- n>cxx20</c-><c- p>;</c->

  <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
  <c- k>class</c-> <c- nc>point</c-> <c- p>{</c->
    <c- n>interface</c-><c- p>(</c-><c- n>cxx20</c-><c- p>)</c-> <c- p>{</c->
      <c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>,</c-> <c- n>z</c-><c- p>;</c->
    <c- p>}</c->

    <c- n>interface</c-><c- p>(</c-><c- n>cxx23</c-><c- p>)</c-> <c- n>T</c-> <c- n>w</c-><c- p>;</c->

  <c- k>public</c-><c- o>:</c->
    <c- n>interface</c-><c- p>(</c-><c- n>cxx20</c-><c- p>)</c-> <c- p>{</c->
      <c- n>point</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>)</c->
        <c- o>:</c-> <c- n>x</c-><c- p>(</c-><c- n>x</c-><c- p>),</c-> <c- n>y</c-><c- p>(</c-><c- n>y</c-><c- p>),</c-> <c- n>z</c-><c- p>(</c-><c- n>z</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

      <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
        <c- k>return</c-> <c- n>x</c-> <c- o>+</c-> <c- n>y</c-> <c- o>+</c-> <c- n>z</c-><c- p>;</c->
      <c- p>}</c->
    <c- p>}</c->

    <c- n>interface</c-><c- p>(</c-><c- n>cxx23</c-><c- p>)</c-> <c- p>{</c->
      <c- n>point</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>x</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>y</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>z</c-><c- p>,</c-> <c- k>const</c-> <c- n>T</c-> <c- o>&amp;</c-><c- n>w</c-> <c- o>=</c-> <c- n>T</c-><c- p>(</c-><c- mi>0</c-><c- p>))</c-> 
        <c- o>:</c-> <c- n>x</c-><c- p>(</c-><c- n>x</c-><c- p>),</c-> <c- n>y</c-><c- p>(</c-><c- n>y</c-><c- p>),</c-> <c- n>z</c-><c- p>(</c-><c- n>z</c-><c- p>),</c-> <c- n>w</c-><c- p>(</c-><c- n>w</c-><c- p>)</c-> <c- p>{</c-> <c- p>}</c->

      <c- n>T</c-> <c- n>sum</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c->
        <c- k>return</c-> <c- n>x</c-> <c- o>+</c-> <c- n>y</c-> <c- o>+</c-> <c- n>z</c-> <c- o>+</c-> <c- n>w</c-><c- p>;</c->
      <c- p>}</c->
    <c- p>}</c->
  <c- p>};</c->
<c- p>}</c-> <c- c1>// namespace std</c->
</pre>
   <p>Now we can use the type in a variety of ways:</p>
<pre class="highlight"><c- c1>// A pointer to: interface(&lt;implementation-defined-default>) std::point&lt;int>.</c->
<c- n>std</c-><c- o>::</c-><c- n>point</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>;</c->

<c- c1>// Same as above.</c->
<c- n>interface</c-><c- p>()</c-> <c- n>std</c-><c- o>::</c-><c- n>point</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>;</c->

<c- c1>// A pointer to: The C++20 std::point&lt;int>.</c->
<c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>point</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>;</c->

<c- c1>// A pointer to: The C++23 std::point&lt;int>.</c->
<c- c1>// This is usable with an interface taking the C++23-or-later type below.</c->
<c- c1>// The object itself might be a little larger than necessary,</c->
<c- c1>// but should not otherwise have other performance overhead.</c->
<c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>point</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>;</c->

<c- c1>// A pointer to: The C++23 or later std::point&lt;int>.</c->
<c- c1>// Use of this object will involve some indirect-access overheads.</c->
<c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- o>+</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>point</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>*</c-><c- n>x</c-><c- p>;</c->
</pre>
   <h2 class="heading settled" data-level="12" id="olang"><span class="secno">12. </span><span class="content">Other Languages</span><a class="self-link" href="#olang"></a></h2>
   <p>Many other languages following this fat-pointer-on-interfaces technique, including:</p>
   <ul>
    <li data-md>
     <p>Go: go’s interface types are runtime generated fat pointers containing
a pointer to the object and a pointer to a fixed-offset table of
function pointers that can be referenced just like a vtable in the
receiver, but are generated by a linear search of a sorted list of
function signatures by name (literally by string comparisons, at
runtime). It also uses a fat pointer setup for slices.  The combination
allows for almost complete decoupling of ABI between translation units that
communicate only through interface types.</p>
    <li data-md>
     <p>Swift: Swift uses vtables in all objects by default, and <code class="highlight"><c- k>virtual</c-></code> methods
actually fall back on a runtime message resolution like Objective-C uses,
allowing runtime addition and proxying of methods as well as some
interesting resilience and ABI stability enhancements on otherwise plain
objects.  Where fat pointers come in, in this case implemented by passing an
extra implicit table argument in addition to an object, is Protocol objects
and APIs.  A function that takes a protocol object gets a fixed-offset table
of pointers to the methods, and possibly data, that are listed in the
protocol specific to the object passed in.  This is part of how they allow
interesting things like static calls to methods added at runtime in the same
TU, and the implementation of protocols using those methods for a type in
dynamically loaded code.</p>
    <li data-md>
     <p>Rust: Types are static by default, generics work essentially like
templates.  Fat pointers are used in a couple of different ways, first
they’re used for references to runtime-sized slice types.  More
significantly, they’re used to implement trait objects.  This is not
quite like Go’s setup in that the object has to have an explicit
implementation of the trait, which allows the compiler to generate the table
rather than having to do it at runtime on first use, but
the usage is much the same.  It allows an API writer to select either
entirely static replicated implementation with generics and trait
bounds or the indirected trait object that has some runtime overhead
but will work with any type that implements the protocol now or in the
future.</p>
   </ul>
   <h2 class="heading settled" data-level="13" id="hdi"><span class="secno">13. </span><span class="content">How Do I?</span><a class="self-link" href="#hdi"></a></h2>
   <p>In this section, we’ll walk though a number of use cases and discuss how they’ll work with this proposal...</p>
   <ul>
    <li data-md>
     <p>I have code compiled for C++20 that uses modules. How can I use it in C++23 code?</p>
   </ul>
<pre class="highlight"><c- n>import</c-> <c- n>SomeCXX20Code</c-><c- p>;</c->
<c- c1>// Now use the exported things as you would expect.</c->
</pre>
   <p>The implementation is allowed to automatically assign the cxx20 interface tag to all of the things in the module (and although the standard may not be able to mandate it, it should do so).</p>
   <ul>
    <li data-md>
     <p>I have code compiled for C++20 that does not use modules. How can I use it in C++23 code?</p>
   </ul>
<pre class="highlight"><c- cp>#include</c-> &lt;stdinterface>
<c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><c- p>)</c-> <c- p>{</c->
<c- cp>#include</c-> &lt;SomeCXX20Code.h>
<c- p>}</c->
<c- c1>// Now use the included things as you would expect.</c->
</pre>
   <p>The interface block will implicitly assign the cxx20 interface tag to everything in the included file, and since nothing in that code uses interfaces, everything should work naturally.</p>
   <ul>
    <li data-md>
     <p>Okay, it can’t be that simple. What’s the catch?</p>
   </ul>
   <p>The catch is that types from the standard library that are used with that C++20 code are not the same types as the standard-library types used in the rest of your C++23 code. So this won’t work...</p>
<pre class="highlight"><c- cp>#include</c-> &lt;stdinterface>
<c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><c- p>)</c-> <c- p>{</c->
<c- b>void</c-> <c- n>foo</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>&amp;</c-><c- n>v</c-><c- p>);</c->
<c- p>}</c->
<c- p>...</c->
<c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>v</c-><c- p>;</c->
<c- n>foo</c-><c- p>(</c-><c- n>v</c-><c- p>);</c-> <c- c1>// illformed; no conversion</c->
        <c- c1>// from interface(std::cxx23) std::vector&lt;int>&amp; to</c->
        <c- c1>//   interface(std::cxx20) std::vector&lt;int>&amp;</c->
</pre>
   <p>But the point here is that:</p>
   <ol>
    <li data-md>
     <p>Both the C++20 and C++23 types can simultaneously coexist in your program (they’re different types in every respect - no ODR or linking problems). So you might need to make copies on interfaces here, but this is all well-defined C++ code and the programmers can figure out the best way to handle this for their applications.</p>
    <li data-md>
     <p>This is a one-time transition, and in the future we can use better facilities provided to manage these kinds of transitions.</p>
   </ol>
   <ul>
    <li data-md>
     <p>Given that C++20 and C++23 standard-library types are different types, can I provide different function overloads for them?</p>
   </ul>
   <p>Yes, they’re different types. That means that you can provide different overloads for them, different template specializations for them, and so on.</p>
<pre class="highlight"><c- cp>#include</c-> &lt;stdinterface>
<c- p>...</c->
<c- b>void</c-> <c- n>foo</c-><c- p>(</c-><c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>&amp;</c-><c- n>x</c-><c- p>)</c-> <c- p>{</c-> <c- p>...</c-> <c- p>}</c->
<c- b>void</c-> <c- n>foo</c-><c- p>(</c-><c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>&amp;</c-><c- n>y</c-><c- p>)</c-> <c- p>{</c-> <c- p>...</c-> <c- p>}</c->
</pre>
   <p>but to be resilient against future changes, you might write:</p>
<pre class="highlight"><c- cp>#include</c-> &lt;stdinterface>
<c- p>...</c->
<c- b>void</c-> <c- n>foo</c-><c- p>(</c-><c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>&amp;</c-><c- n>x</c-><c- p>)</c-> <c- p>{</c-> <c- p>...</c-> <c- p>}</c->
<c- b>void</c-> <c- n>foo</c-><c- p>(</c-><c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- o>+</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>&amp;</c-><c- n>y</c-><c- p>)</c-> <c- p>{</c-> <c- p>...</c-> <c- p>}</c->
</pre>
   <p>and now the second overload will handle all versions of the standard in the future. There will be some performance overhead as we’ve now essentially made all member functions on y virtual, although the compiler is certainly free to specialize for the case where the object is of type std::cxx23::vector itself - and the programmer can also explicitly specialize by using dynamic_cast in the definition of the function (although I wouldn’t recommend it, unless the programmer also arranges for some way to test the non-specialized code).</p>
   <p>Template instantiation and specialization also work as they usually do:</p>
<pre class="highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- n>T</c-><c- o>></c->
<c- b>unsigned</c-> <c- n>foo</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> <c- k>sizeof</c-><c- p>(</c-><c- n>T</c-><c- p>);</c-> <c- p>}</c->
<c- p>...</c->
<c- c1>// This returns whatever it did in C++20 for std::vector&lt;int>, probably 24.</c->
<c- n>foo</c-><c- o>&lt;</c-><c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>>></c-><c- p>();</c->

<c- c1>// This returns whatever it should now in C++23, probably also 24.</c->
<c- n>foo</c-><c- o>&lt;</c-><c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>>></c-><c- p>();</c->
<c- n>foo</c-><c- o>&lt;</c-><c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>>></c-><c- p>();</c-> <c- c1>// if cxx23 is the default, this is the same as above.</c->
</pre>
   <p class="note" role="note"><span>Note:</span> On the design space here: it is tempting to think of objects with unresolved interface tags as real (complete) "proxy objects" with sizes and so on. There are several alternatives here that don’t really seem to work. First, we could have proxy objects as real objects that are first-class values. The problem here comes from functions that want the proxy itself by pointer, as automatic wrapping would require heap allocating the proxy, and then it would need to live for an indefinite period of time (its lifetime should be tied to that of the original object, but we have no good way to do that). An alternative would be to make the user explicitly manage the lifetime of the proxy object, but the ergonomics are not good (and the user of the interface in question might also not own the object or have any way to tie the lifetime of the newly-allocated proxy object to the original). We could say that, somewhat like references, taking the address of the proxy object yields the underlying object, so we never pass pointers to the proxy objects (they’re only used for pass by value), but then the size of the proxy object would be inconsistent with the size of the storage represented by the memory at the taken address.</p>
   <ul>
    <li data-md>
     <p>How can the standard library write a class that provides it’s existing external interface to C++20 clients, and a new interface to C++23 clients?</p>
   </ul>
<pre class="highlight"><c- cp>#include</c-> &lt;stdinterface>
<c- p>...</c->
<c- k>struct</c-> <c- n>point</c-> <c- p>{</c->
  <c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><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- n>z</c-><c- p>;</c->
    <c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- p>)</c-> <c- b>int</c-> <c- n>w</c-><c- p>;</c->

    <c- b>int</c-> <c- nf>get_x</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>x</c-><c- p>;</c-> <c- p>}</c->

    <c- b>int</c-> <c- nf>get_w</c-><c- p>()</c-> <c- k>const</c-> <c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- p>)</c-> <c- p>{</c-> <c- k>return</c-> <c- n>w</c-><c- p>;</c-> <c- p>}</c->

    <c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- p>)</c-> <c- p>{</c->
      <c- b>bool</c-> <c- n>only_for_cxx23</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> true<c- p>;</c-> <c- p>}</c->
    <c- p>}</c->
  <c- p>}</c->
<c- p>};</c->

<c- c1>// sizeof(interface(std::cxx20) point) == 12.</c->
<c- c1>// sizeof(interface(std::cxx23) point) == 16;</c->
</pre>
   <p>This class provides an existing interface to C++20 clients, using its exiting ABI, while simultaneously providing an expanded interface to C++23 clients.</p>
   <ul>
    <li data-md>
     <p>How can I (not the standard library) write a class that provides it’s existing external interface to C++20 clients, and a new interface to C++23 clients?</p>
   </ul>
   <p>You do this in much the same way as the standard library, but you only need to consider cxx20 to be special as far as the ABI goes. Going forward, you likely want to decouple your interface updating strategy from that of the C++ standard.</p>
<pre class="highlight"><c- cp>#include</c-> &lt;stdinterface>
<c- p>...</c->
<c- n>interface</c-> <c- nl>v2</c-> <c- p>:</c-> <c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><c- p>;</c->
<c- n>interface</c-> <c- nl>v3</c-> <c- p>:</c-> <c- n>v2</c-><c- p>;</c->
<c- p>...</c->
<c- k>struct</c-> <c- n>point</c-> <c- p>{</c->
  <c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx20</c-><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- n>z</c-><c- p>;</c->
    <c- n>interface</c-><c- p>(</c-><c- n>v2</c-><c- p>)</c-> <c- b>int</c-> <c- n>w</c-><c- p>;</c->

    <c- b>int</c-> <c- nf>get_x</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>x</c-><c- p>;</c-> <c- p>}</c->

    <c- b>int</c-> <c- nf>get_w</c-><c- p>()</c-> <c- k>const</c-> <c- n>interface</c-><c- p>(</c-><c- n>v2</c-><c- p>)</c-> <c- p>{</c-> <c- k>return</c-> <c- n>w</c-><c- p>;</c-> <c- p>}</c->

    <c- n>interface</c-><c- p>(</c-><c- n>v3</c-><c- p>)</c-> <c- p>{</c->
      <c- b>bool</c-> <c- n>only_for_v3</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> true<c- p>;</c-> <c- p>}</c->
    <c- p>}</c->
  <c- p>}</c->
<c- p>};</c->

<c- c1>// sizeof(interface(std::cxx20) point) == 12.</c->
<c- c1>// sizeof(interface(v2) point) == 16;</c->
<c- c1>// sizeof(interface(v3) point) == 16;</c->
</pre>
   <ul>
    <li data-md>
     <p>What if I don’t care about C++20 ABI compatibility, and I just want to manage by interface stability going forward?</p>
   </ul>
   <p>In that case, you can ignore the standard tags and just add interface declarations as appropriate.</p>
<pre class="highlight"><c- n>interface</c-> <c- n>v1</c-><c- p>;</c->
<c- n>interface</c-> <c- nl>v2</c-> <c- p>:</c-> <c- n>v1</c-><c- p>;</c->
<c- p>...</c->
<c- k>struct</c-> <c- n>point</c-> <c- p>{</c->
  <c- n>interface</c-><c- p>(</c-><c- n>v1</c-><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- n>z</c-><c- p>;</c->
    <c- n>interface</c-><c- p>(</c-><c- n>v2</c-><c- p>)</c-> <c- b>int</c-> <c- n>w</c-><c- p>;</c->

    <c- b>int</c-> <c- nf>get_x</c-><c- p>()</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- n>x</c-><c- p>;</c-> <c- p>}</c->

    <c- b>int</c-> <c- nf>get_w</c-><c- p>()</c-> <c- k>const</c-> <c- n>interface</c-><c- p>(</c-><c- n>v2</c-><c- p>)</c-> <c- p>{</c-> <c- k>return</c-> <c- n>w</c-><c- p>;</c-> <c- p>}</c->

    <c- n>interface</c-><c- p>(</c-><c- n>v3</c-><c- p>)</c-> <c- p>{</c->
      <c- b>bool</c-> <c- n>only_for_v3</c-><c- p>()</c-> <c- p>{</c-> <c- k>return</c-> true<c- p>;</c-> <c- p>}</c->
    <c- p>}</c->
  <c- p>}</c->
<c- p>};</c->

<c- c1>// sizeof(interface(v1) point) == 12.</c->
<c- c1>// sizeof(interface(v2) point) == 16;</c->
<c- c1>// sizeof(interface(v3) point) == 16;</c->
</pre>
   <ul>
    <li data-md>
     <p>What if I’m writing a function that takes standard-library types as parameters, and it might be called by clients using current and future revisions of C++?</p>
   </ul>
   <p>Then you’ll want to take these unresolved-interface-qualified types.</p>
<pre class="highlight"><c- b>void</c-> <c- nf>foo</c-><c- p>(</c-><c- n>interface</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>cxx23</c-><c- o>+</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>vector</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- o>&amp;</c-><c- n>x</c-><c- p>)</c-> <c- p>{</c->
 <c- c1>// We can be called with a C++23 vector, or a C++26 vector, or any later version.</c->
<c- p>}</c->
</pre>
   <h2 class="heading settled" data-level="14" id="odr"><span class="secno">14. </span><span class="content">ODR and Definition Flexibility</span><a class="self-link" href="#odr"></a></h2>
   <p>There are some choices around how we adjust our ODR rules and these have design implications for the feature. We will need to adjust our ODR rules to allow for multiple definitions of types which are not exactly the same, but rather, one definition includes entities with interface qualifiers not found in the other.</p>
   <p>We might also decide to allow reordering of member declarations within a type while deciding equivalence. Allowing for this kind of reordering may require a more-resilient indexing scheme into the type metadata (e.g., instead of a fixed-index vtable, a hash lookup or binary search might be needed to find member offsets).</p>
   <p>We might also decide to allow for renaming of things. This could be done by allowing for the association of a UUID (used, e.g., for mangling instead of the name itself) with entities that are allowed to be renamed.</p>
   <h2 class="heading settled" data-level="15" id="prop"><span class="secno">15. </span><span class="content">Proposal</span><a class="self-link" href="#prop"></a></h2>
   <h3 class="heading settled" data-level="15.1" id="itags"><span class="secno">15.1. </span><span class="content">Interface Tags</span><a class="self-link" href="#itags"></a></h3>
   <p>First, this proposal introduces the concept of an interface tag. An interface tag identifies an interface version and has one or two properties:</p>
   <ol>
    <li data-md>
     <p>A name. This name has the usual properties of names in C++: it has a scope, it may be qualified, and so on.</p>
    <li data-md>
     <p>Optionally, a parent. An interface may specify an interface from which it inherits. Only single inheritance is permitted (i.e., interface versions have only a linear history).</p>
   </ol>
<pre class="highlight"><c- c1>// Declares an interface tag:</c->
<c- n>interface</c-> <c- n>v1</c-><c- p>;</c->
<c- c1>// Declares an interface tag that inherits from the one above.</c->
<c- n>interface</c-> <c- nl>v2</c-> <c- p>:</c-> <c- n>v1</c-><c- p>;</c->
</pre>
   <p>The intent of this proposal is that each version of the standard will define an interface tag associated with that version of the standard, along with the tags defined in previous revisions of the standard, with an appropriate inheritance structure. For example, we might have:</p>
<pre class="highlight"><c- k>namespace</c-> <c- n>std</c-> <c- p>{</c->

  <c- n>interface</c-> <c- n>cxx20</c-><c- p>;</c->
  <c- n>interface</c-> <c- nl>cxx23</c-> <c- p>:</c-> <c- n>cxx20</c-><c- p>;</c->

<c- p>}</c->
</pre>
   <p class="note" role="note"><span>Note:</span> It is expected that implementations will treat the cxx20 tag as a special case for the purpose of maintaining ABI compatibility with code compiled using tools complying with previous revisions of the C++ standard. Specifically, entities with the cxx20 interface tag may follow different name-mangling rules than other entities.</p>
   <p class="issue" id="issue-f0be8bf3"><a class="self-link" href="#issue-f0be8bf3"></a> Can interfaces themselves be template arguments and, thus, be dependent?</p>
   <h3 class="heading settled" data-level="15.2" id="blks"><span class="secno">15.2. </span><span class="content">Interface Blocks</span><a class="self-link" href="#blks"></a></h3>
   <p>Recognizing that it is often the case that an interface will apply to everything in large sections of source code, this proposal introduces interface blocks. An interface block can appear at any scope (i.e., namespace scope, class scope, function-scope, etc.) and only cause all declarations and definitions within the interface block to have an implicit interface qualifier with the provided interface tag.</p>
<pre class="highlight"><c- k>namespace</c-> <c- n>foo</c-> <c- p>{</c->
  <c- n>interface</c-><c- p>(</c-><c- n>v1</c-><c- p>)</c-> <c- p>{</c->
    <c- k>struct</c-> <c- n>x</c-><c- p>;</c->
  <c- p>}</c->

  <c- n>interface</c-><c- p>(</c-><c- n>v2</c-><c- p>)</c-> <c- p>{</c->
    <c- k>struct</c-> <c- n>y</c-><c- p>;</c->
    <c- k>struct</c-> <c- nl>x</c-> <c- p>:</c-> <c- k>public</c-> <c- n>y</c-><c- p>;</c->
  <c- p>}</c->

  <c- k>struct</c-> <c- n>z</c-> <c- p>{</c->
    <c- n>interface</c-><c- p>(</c-><c- n>v1</c-><c- p>)</c-> <c- p>{</c->
      <c- b>int</c-> <c- n>x</c-><c- p>;</c->
    <c- p>}</c->

    <c- n>interface</c-><c- p>(</c-><c- n>v2</c-><c- p>)</c-> <c- p>{</c->
      <c- b>int</c-> <c- n>x</c-><c- p>;</c->
      <c- b>int</c-> <c- n>y</c-><c- p>;</c->
    <c- p>}</c->
  <c- p>};</c->
<c- p>}</c->
</pre>
   <p class="note" role="note"><span>Note:</span> Formally, interface blocks do not introduce new scopes, but are merely syntactic sugar for adding the interface qualifier to everything relevant inside the curly braces. This might seem strange, but in context this makes sense because the interface qualifier itself has a name-scoping-like effect, and so from the programmer’s perspective, the construct should have the behavior implied by the braces.</p>
   <p>An interface block with an empty interface restores use of the default interface.</p>
   <h3 class="heading settled" data-level="15.3" id="quals"><span class="secno">15.3. </span><span class="content">Interface Qualifiers</span><a class="self-link" href="#quals"></a></h3>
   <p>This proposal introduces a new interface qualifier. There are two kinds of interface qualifiers for:</p>
   <ol>
    <li data-md>
     <p>Resolved interfaces - These refer to a specific, named interface.</p>
    <li data-md>
     <p>Unresolved interfaces - These refer to a named base interface, and the object might have that interface or any interface (transitively) inheriting from it.</p>
   </ol>
<pre class="highlight"><c- c1>// A qualifier for the interface tag v1.</c->
<c- n>interface</c-><c- p>(</c-><c- n>v1</c-><c- p>)</c->
<c- c1>// A qualifier for the interface tag v1 or any interface inheriting from it.</c->
<c- c1>// This is called an unresolved interface.</c->
<c- n>interface</c-><c- p>(</c-><c- n>v1</c-><c- o>+</c-><c- p>)</c->
</pre>
   <p>These qualifiers can appear on functions, variables, and so on. Interface qualifiers become part of the type. This has all of the usual properties (e.g., they can be used for overloading, template specialization, and so on).</p>
   <p>There is an implementation-defined default interface tag applied to all declarations and definitions. This default must be the same for all entities within a module.</p>
   <p class="note" role="note"><span>Note:</span> This is to allow the implementation to import modules previously compiled under previous revisions of the C++ standard and have entities in those modules have the "older" interface tag.</p>
   <p>An interface qualifier with an empty interface tag specifies that the default interface is to be used.</p>
   <p>When performing name lookup, there might be multiple available names in a scope that only differ by their interface tag. In this case, names with an interface tag matching those of the object (for member access), or parameters (analogous to ADL) for any calls, are preferred.</p>
   <h4 class="heading settled" data-level="15.3.1" id="qualsadd"><span class="secno">15.3.1. </span><span class="content">Interface Additivity</span><a class="self-link" href="#qualsadd"></a></h4>
   <p>Entities cannot have more than one interface, although if an entity has an interface qualifier (explicit or implicit) for both an interface and an interface from which it inherits, the parent interface qualifier is ignored. Otherwise, the program is illformed.</p>
   <p>Members of an aggregate must all have interfaces with a common base interface, otherwise the program is illformed.</p>
   <p>The set of interface-visible, qualified names associated with an interface tag, including any explicitly-deleted names, must be a superset of the names associated with the tag from which it inherits. Otherwise, the program is illformed. Interface-visible names are those which are namespace scope, public, or used (even in an unevaluated context) by interface-visible entities with inline linkage.</p>
   <p>Entities within the same scope with the same name and type (ignoring interface tags) that have storage must be aliases to the same object (i.e., must share that storage).</p>
   <p class="note" role="note"><span>Note:</span> The above rules are intended to ensure that interface inheritance is strictly additive (although additive in this context does include the ability to explicitly make names unavailable by deleting them) and storage sharing takes place as needed.</p>
   <p>Interface qualifiers on fundamental types are ignored. The implementation may define extended fundamental types on which interface qualifiers are ignored. Collectively, these are called interface oblivious types.</p>
   <p class="note" role="note"><span>Note:</span> The standard library provides a type trait that can be used to determine if interface qualifiers will be ignored for a given base type.</p>
   <h4 class="heading settled" data-level="15.3.2" id="qualsur"><span class="secno">15.3.2. </span><span class="content">Unresolved Interfaces</span><a class="self-link" href="#qualsur"></a></h4>
   <p>Types with unresolved interfaces are distinct from types with resolved interfaces to the same base interface tags.</p>
   <p class="note" role="note"><span>Note:</span> dynamic_cast, and other associated mechanisms, can be used to determine if an object with a given type can be converted to another type (perhaps differing only in the interface qualifier).</p>
   <p>Variables with types with unresolved interfaces may hold values of the same base type and any interface tag that (transitively) inherits from the provided base interface or the base interface itself.</p>
   <p class="note" role="note"><span>Note:</span> The restriction to types with explicitly-provided interface tags is needed to permit types to omit their hidden metadata fields associated with providing interface support.</p>
   <p>offsetof cannot be applied to types with unresolved interfaces, and neither can sizeof/alignof. These can only be used to make pointer/reference types.</p>
   <p class="note" role="note"><span>Note:</span> The offsets of members within a type with an unresolved interface are not available at compile time, and can be different for different values.</p>
   <p>All interface-public members can be accessed from a type with an unresolved interface, but all types on those interfaces will be act as though they’re also unresolved. If any of these types do not support use with unresolved interfaces, the program is illformed.</p>
   <h3 class="heading settled" data-level="15.4" id="hdr"><span class="secno">15.4. </span><span class="content">Header &lt;stdinterface></span><a class="self-link" href="#hdr"></a></h3>
<pre class="highlight"><c- k>namespace</c-> <c- n>std</c-> <c- p>{</c->
  <c- n>interface</c-> <c- n>cxx20</c-><c- p>;</c->
  <c- n>interface</c-> <c- nl>cxx23</c-> <c- p>:</c-> <c- n>cxx20</c-><c- p>;</c->


  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>struct</c-> <c- n>is_interface_oblivious</c-><c- p>;</c->

  <c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- kr>inline</c-> <c- k>constexpr</c-> <c- b>bool</c-> <c- n>is_interface_oblivious_v</c-> <c- o>=</c-> <c- n>is_interface_oblivious</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>value</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>is_interface_oblivious can be used to detect if the type is interface oblivious (i.e., ignores interface qualifiers). This is true for fundamental types and may also be true for an implementation-defined set of other implementation-defined types. Otherwise, it is false.</p>
   <p class="issue" id="issue-509ca4da"><a class="self-link" href="#issue-509ca4da"></a> Other traits should be provided. A traits to strip off the interface qualifier seems likely needed.</p>
   <h2 class="heading settled" data-level="16" id="ack"><span class="secno">16. </span><span class="content">Acknowledgments</span><a class="self-link" href="#ack"></a></h2>
   <p>We thank Nevin Liber, Corentin Jabot, Niall Douglas, Bjarne Stroustrup, Arthur O’Dwyer, Tom Honermann, Gabriel Dos Reis, Bryce Adelstein Lelbach, Richard Smith, Peter Dimov, Peter Bindels, Nathan Myers, Mathias Stearn, Caleb Sunstrum, Stephan T. Lavavej, Ben Craig, Michael Hava, Steve Downey, Davis Herring, Attila Fehér, David Stone, Arvid Norberg, Tony Van Eerd, Bronek Kozicki, and Jon Chesterfield for providing feedback.</p>
   <p>This research was supported by the Exascale Computing Project (17-SC-20-SC), a collaborative effort of two U.S. Department of Energy organizations (Office of Science and the National Nuclear Security Administration) responsible for the planning and preparation of a capable exascale ecosystem, including software, applications, hardware, advanced system engineering, and early testbed platforms, in support of the nation’s exascale computing imperative. Additionally, this research used resources of the Argonne Leadership Computing Facility, which is a DOE Office of Science User Facility supported under Contract DE-AC02-06CH11357.</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="issues-index"><span class="content">Issues Index</span><a class="self-link" href="#issues-index"></a></h2>
  <div style="counter-reset:issue">
   <div class="issue"> Can interfaces themselves be template arguments and, thus, be dependent?<a href="#issue-f0be8bf3"> ↵ </a></div>
   <div class="issue"> Other traits should be provided. A traits to strip off the interface qualifier seems likely needed.<a href="#issue-509ca4da"> ↵ </a></div>
  </div>