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

/* color variables included separately for reliability */

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

	html {
	}

	body {
		counter-reset: example figure issue;

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	p {
		margin: 1em 0;
	}

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

	/* Do something nice. */

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

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

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

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

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

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

	img {
		border-style: none;
	}

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


/*
Alternate table alignment rules

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

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

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

Possible extra rowspan handling

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

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

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


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

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

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

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

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

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

		.toc li {
			clear: both;
		}

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

.outdated-warning span {
	display: block;
}

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

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

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

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

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



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    --heading-text: #005a9c;

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

    --algo-border: #def;

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

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

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

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

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

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

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

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

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

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

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

    --datacell-border: silver;

    --indexinfo-text: #707070;

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

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

    --editedrec-bg: darkorange;
}

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

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

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

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

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

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

        --heading-text: #8af;

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

        --algo-border: #456;

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

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

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

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

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

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

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

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

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

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

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

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

        --datacell-border: silver;

        --indexinfo-text: #aaa;

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

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

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

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

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

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

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

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

    c-[a] { color: #d33682 } /* Keyword.Declaration */
    c-[b] { color: #d33682 } /* Keyword.Type */
    c-[c] { color: #2aa198 } /* Comment */
    c-[d] { color: #2aa198 } /* Comment.Multiline */
    c-[e] { color: #268bd2 } /* Name.Attribute */
    c-[f] { color: #b58900 } /* Name.Tag */
    c-[g] { color: #cb4b16 } /* Name.Variable */
    c-[k] { color: #d33682 } /* Keyword */
    c-[l] { color: #657b83 } /* Literal */
    c-[m] { color: #657b83 } /* Literal.Number */
    c-[n] { color: #268bd2 } /* Name */
    c-[o] { color: #657b83 } /* Operator */
    c-[p] { color: #657b83 } /* Punctuation */
    c-[s] { color: #6c71c4 } /* Literal.String */
    c-[t] { color: #6c71c4 } /* Literal.String.Single */
    c-[u] { color: #6c71c4 } /* Literal.String.Double */
    c-[ch] { color: #2aa198 } /* Comment.Hashbang */
    c-[cp] { color: #2aa198 } /* Comment.Preproc */
    c-[cpf] { color: #2aa198 } /* Comment.PreprocFile */
    c-[c1] { color: #2aa198 } /* Comment.Single */
    c-[cs] { color: #2aa198 } /* Comment.Special */
    c-[kc] { color: #d33682 } /* Keyword.Constant */
    c-[kn] { color: #d33682 } /* Keyword.Namespace */
    c-[kp] { color: #d33682 } /* Keyword.Pseudo */
    c-[kr] { color: #d33682 } /* Keyword.Reserved */
    c-[ld] { color: #657b83 } /* Literal.Date */
    c-[nc] { color: #268bd2 } /* Name.Class */
    c-[no] { color: #268bd2 } /* Name.Constant */
    c-[nd] { color: #268bd2 } /* Name.Decorator */
    c-[ni] { color: #268bd2 } /* Name.Entity */
    c-[ne] { color: #268bd2 } /* Name.Exception */
    c-[nf] { color: #268bd2 } /* Name.Function */
    c-[nl] { color: #268bd2 } /* Name.Label */
    c-[nn] { color: #268bd2 } /* Name.Namespace */
    c-[py] { color: #268bd2 } /* Name.Property */
    c-[ow] { color: #657b83 } /* Operator.Word */
    c-[mb] { color: #657b83 } /* Literal.Number.Bin */
    c-[mf] { color: #657b83 } /* Literal.Number.Float */
    c-[mh] { color: #657b83 } /* Literal.Number.Hex */
    c-[mi] { color: #657b83 } /* Literal.Number.Integer */
    c-[mo] { color: #657b83 } /* Literal.Number.Oct */
    c-[sa] { color: #6c71c4 } /* Literal.String.Affix */
    c-[sb] { color: #6c71c4 } /* Literal.String.Backtick */
    c-[sc] { color: #6c71c4 } /* Literal.String.Char */
    c-[dl] { color: #6c71c4 } /* Literal.String.Delimiter */
    c-[sd] { color: #6c71c4 } /* Literal.String.Doc */
    c-[se] { color: #6c71c4 } /* Literal.String.Escape */
    c-[sh] { color: #6c71c4 } /* Literal.String.Heredoc */
    c-[si] { color: #6c71c4 } /* Literal.String.Interpol */
    c-[sx] { color: #6c71c4 } /* Literal.String.Other */
    c-[sr] { color: #6c71c4 } /* Literal.String.Regex */
    c-[ss] { color: #6c71c4 } /* Literal.String.Symbol */
    c-[fm] { color: #268bd2 } /* Name.Function.Magic */
    c-[vc] { color: #cb4b16 } /* Name.Variable.Class */
    c-[vg] { color: #cb4b16 } /* Name.Variable.Global */
    c-[vi] { color: #cb4b16 } /* Name.Variable.Instance */
    c-[vm] { color: #cb4b16 } /* Name.Variable.Magic */
    c-[il] { color: #657b83 } /* Literal.Number.Integer.Long */
}
</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P3834R0<br>Defaulting the Compound Assignment Operators</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Published Proposal,
    <time class="dt-updated" datetime="2025-07-09">2025-07-09</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt class="editor">Authors:
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:mjtaylor214@hotmail.com">Matthew Taylor</a>
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:waffl3x@baylibre.com">Alex (Waffl3x)</a>
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:oliver.rosten@gmail.com">Oliver Rosten</a>
     <dt>Audience:
     <dd>SG17
     <dt>Project:
     <dd>ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <div class="p-summary" data-fill-with="abstract">
   <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2>
   <p>The compound assignment operators have a universally-accepted default meaning. This paper proposes reducing boilerplate by being able to default those operators.</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="#principles"><span class="secno">2</span> <span class="content">Design Principles</span></a>
    <li>
     <a href="#proposal"><span class="secno">3</span> <span class="content">Proposal</span></a>
     <ol class="toc">
      <li>
       <a href="#proposal-edges"><span class="secno">3.1</span> <span class="content">Minor Edge Cases</span></a>
       <ol class="toc">
        <li><a href="#proposal-const"><span class="secno">3.1.1</span> <span class="content">cv-qualification and ref-qualification</span></a>
        <li><a href="#proposal-implicit"><span class="secno">3.1.2</span> <span class="content">Implicit conversion to parameter types of the underlying operator</span></a>
        <li><a href="#proposal-xobj-type"><span class="secno">3.1.3</span> <span class="content">Explicit object parameter types</span></a>
        <li><a href="#proposal-self-assignment"><span class="secno">3.1.4</span> <span class="content">Self-assignment</span></a>
       </ol>
      <li><a href="#proposal-function-body"><span class="secno">3.2</span> <span class="content"><code class="highlight"><c- o>=</c-> <c- k>default</c-></code> is a function body</span></a>
     </ol>
    <li><a href="#boilerplate"><span class="secno">4</span> <span class="content">Are We Creating Tomorrow’s Boilerplate?</span></a>
    <li>
     <a href="#alternatives"><span class="secno">5</span> <span class="content">Alternatives Considered</span></a>
     <ol class="toc">
      <li><a href="#proposal-plus-equals"><span class="secno">5.1</span> <span class="content">Defining <code class="highlight"><c- k>operator</c-><c- o>+</c-></code> in terms of <code class="highlight"><c- k>operator</c-><c- o>+=</c-></code></span></a>
      <li><a href="#alternatives-forwarding"><span class="secno">5.2</span> <span class="content">A Perfect Forwarding Compound Assignment Operator Template</span></a>
      <li><a href="#alternatives-dynamite"><span class="secno">5.3</span> <span class="content">A Magic Pseudo Operator</span></a>
      <li><a href="#alternatives-reflection"><span class="secno">5.4</span> <span class="content">Reflection Solutions</span></a>
      <li><a href="#alternatives-free-functions"><span class="secno">5.5</span> <span class="content">Free Function Compound Assignment Operator Templates</span></a>
      <li><a href="#alternatives-rewrite"><span class="secno">5.6</span> <span class="content">Rewrite Rule and Implicit Generation of Operators</span></a>
     </ol>
    <li>
     <a href="#Other-papers"><span class="secno">6</span> <span class="content">Other Papers in this Space</span></a>
     <ol class="toc">
      <li><a href="#others-P1046"><span class="secno">6.1</span> <span class="content">P1046 Automatically Generate More Operators</span></a>
      <li><a href="#others-P2952"><span class="secno">6.2</span> <span class="content">P2952 auto&amp; operator=(X&amp;&amp;) = default;</span></a>
      <li><a href="#others-P2953"><span class="secno">6.3</span> <span class="content">P2953 Forbid defaulting operator=(X&amp;&amp;) &amp;&amp;</span></a>
      <li><a href="#others-P3668"><span class="secno">6.4</span> <span class="content">P3668 Defaulting Postfix Increment and Decrement Operations</span></a>
     </ol>
    <li><a href="#acknowledgements"><span class="secno">7</span> <span class="content">Acknowledgements</span></a>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="intro"><span class="secno">1. </span><span class="content">Introduction</span><a class="self-link" href="#intro"></a></h2>
   
The default meaning of the compound assignment operators is universally known and only rarely overloaded to mean anything different. The behaviour of <code class="highlight"><c- k>operator</c-><c- o>+</c-></code> and <code class="highlight"><c- k>operator</c-><c- o>+=</c-></code> with respect to each other is something which does not change in user code. As such, we propose that the language codify this sensible default and allow such operator overloads to be defaulted. The result, in each case, is an implicitly created function body with the generally accepted meaning. This would cut down on unnecessary boilerplate, reduce the surface area for user mistakes, and make operators which have an exotic implementation stand out in user code by virtue of not being defaulted.


   <p>The status quo of the compound assignment operators comes with a lot of boilerplate, which makes for longer code which is slightly harder to reason about. Consider the most basic kind of arithmetic type - a class which wraps an integer:</p>
<pre class="language-cpp highlight"><c- k>struct</c-> <c- nc>int_wrapper</c-><c- p>{</c->
    <c- b>int</c-> <c- n>data_</c-><c- p>;</c->

    <c- n>int_wrapper</c-><c- p>(</c-><c- b>int</c-> <c- n>in</c-><c- p>)</c-> <c- o>:</c-> <c- n>data_</c-><c- p>{</c-><c- n>in</c-><c- p>}</c-> <c- p>{}</c->

<c- p>};</c->

<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>+</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->
<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>int_wrapper</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>){</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>=</c-> <c- n>lhs</c-> <c- o>+</c-> <c- n>rhs</c-><c- p>;</c->
<c- p>}</c->
<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>-</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>-</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->
<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>-=</c-><c- p>(</c-><c- n>int_wrapper</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>){</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>=</c-> <c- n>lhs</c-> <c- o>-</c-> <c- n>rhs</c-><c- p>;</c->
<c- p>}</c->
<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>*</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>*</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->
<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>*=</c-><c- p>(</c-><c- n>int_wrapper</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>){</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>=</c-> <c- n>lhs</c-> <c- o>*</c-> <c- n>rhs</c-><c- p>;</c->
<c- p>}</c->
<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>/</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>/</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->
<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>/=</c-><c- p>(</c-><c- n>int_wrapper</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>){</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>=</c-> <c- n>lhs</c-> <c- o>/</c-> <c- n>rhs</c-><c- p>;</c->
<c- p>}</c->
<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>%</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>%</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->
<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>%=</c-><c- p>(</c-><c- n>int_wrapper</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>){</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>=</c-> <c- n>lhs</c-> <c- o>%</c-> <c- n>rhs</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>None of the individual operations on this class are complex, nor is what the overall class models complex; however the amount of boilerplate required to represent this simple idea means that we spend 50 lines of code covering the basic supported operations (more if the class also emulates bitwise operations). Users of C++ frequently cite complexity and boilerplate as major pain points, sometimes even as a higher frustration than safety <a data-link-type="biblio" href="#biblio-cppdev-2025" title="2025 Annual C++ Developer Survey &apos;Lite&apos;">[CppDev-2025]</a>. We take this as motivation to simplify things by reducing user boilerplate by defaulting the compound assignment operators. After this change, the above code could be rewritten as:</p>
<pre class="language-cpp highlight"><c- k>struct</c-> <c- nc>int_wrapper</c-><c- p>{</c->
    <c- b>int</c-> <c- n>data_</c-><c- p>;</c->

    <c- n>int_wrapper</c-><c- p>(</c-><c- b>int</c-> <c- n>in</c-><c- p>)</c-> <c- o>:</c-> <c- n>data_</c-><c- p>{</c-><c- n>in</c-><c- p>}</c-> <c- p>{}</c->

<c- p>};</c->
<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>+</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->
<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>-</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>-</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->
<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>*</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>*</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->
<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>/</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>/</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->
<c- n>int_wrapper</c-> <c- k>operator</c-><c- o>%</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>int_wrapper</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>data_</c-> <c- o>%</c-> <c- n>rhs</c-><c- p>.</c-><c- n>data_</c-><c- p>};</c->
<c- p>}</c->

<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>-=</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>*=</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>/=</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- n>int_wrapper</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>%=</c-><c- p>(</c-><c- n>int_wrapper</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>int_wrapper</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
</pre>
   <p>We consider this a significant improvement - it is easier for the user to parse this code and see that the class supports the basic arithmetic operations, and the fact that the compound assignment operations are supported is clear and their semantics are easily understood.</p>
   <p>We would be interested in applying this change to the library specification, in order to remove boilerplate function definitions while maintaining the same semantics. The authors intend to bring a paper to do this pending interest in the language feature.</p>
   <p class="note" role="note"><span class="marker">Note:</span> This proposal covers the scope of all overloadable operators which have a compound assignment form, namely <code class="highlight"><c- o>+</c-></code>, <code class="highlight"><c- o>-</c-></code>, <code class="highlight"><c- o>*</c-></code>, <code class="highlight"><c- o>/</c-></code>, <code class="highlight"><c- o>%</c-></code>, <code class="highlight"><c- o>^</c-></code>, <code class="highlight"><c- o>&amp;</c-></code>, <code class="highlight"><c- o>|</c-></code>, <code class="highlight"><c- o>&lt;&lt;</c-></code>, and <code class="highlight"><c- o>>></c-></code>. For the sake of simplicity, most examples will be written in terms of <code class="highlight"><c- k>operator</c-><c- o>+</c-></code> and <code class="highlight"><c- k>operator</c-><c- o>+=</c-></code>, but all operators follow the same semantics.</p>
   <h2 class="heading settled" data-level="2" id="principles"><span class="secno">2. </span><span class="content">Design Principles</span><a class="self-link" href="#principles"></a></h2>
   <p>It is worth noting the principles which we use to guide our design. The overall goal is a net reduction in language complexity and unnecessary boilerplate, however we want to list specifically how we intend to keep to this goal.</p>
   <ol>
    <li data-md>
     <p><strong>The defaulted semantics of an operator must be universally known to be its default behaviour:</strong> Otherwise classes would be significantly harder to reason about, not easier.</p>
    <li data-md>
     <p><strong>A defaulted operator must not be harder to reason about than its canonical implementation:</strong> Otherwise that would obviate the purpose of the proposal. This imposes a low complexity ceiling on how these operations can be specified and prevents certain "clever tricks" or conditional behaviours which might appear to help at first glance.</p>
    <li data-md>
     <p><strong>A class' supported operations should be clearly visible in code and easy to reason about:</strong> This has been previously reinforced by EWG feedback <a data-link-type="biblio" href="#biblio-p1046-ewg" title="EWG comments from the Belfast meeting">[P1046-EWG]</a> and usually means that a class' supported operations should be reasonably local to the class definition.</p>
    <li data-md>
     <p><b>Replacing the implementation of a defaultable operator with <code class="highlight"><c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> must not produce surprising results:</b> In most cases, this means that the behaviour will either be identical to before the change, or produce an error. Users should not be surprised if an overload which previously exhibited non-defaulted behaviour changes its semantics when defaulted.</p>
   </ol>
   <h2 class="heading settled" data-level="3" id="proposal"><span class="secno">3. </span><span class="content">Proposal</span><a class="self-link" href="#proposal"></a></h2>
   <p class="note" role="note"><span class="marker">Note:</span> In this section we use the non-standard term "underlying operator" to refer to the binary arithmetic or bitwise operator which a compound assignment operator calls. For example, the underlying operator of <code class="highlight"><c- k>operator</c-><c- o>+=</c-></code> is <code class="highlight"><c- k>operator</c-><c- o>+</c-></code>.</p>
   <p>We propose that each compound assignment operator overload be a defaultable function. We permit the following signatures on compound assignment operations operating on types <code class="highlight"><c- n>A</c-></code> and <code class="highlight"><c- n>B</c-></code> (where <code class="highlight"><c- n>A</c-></code> and <code class="highlight"><c- n>B</c-></code> may be the same type):</p>
<pre class="language-cpp highlight"><c- n>A</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>A</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>B</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- n>A</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>A</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>B</c-> <c- n>rhs</c-><c- p>)</c->        <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- n>A</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>A</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>B</c-><c- o>&amp;&amp;</c-> <c- n>rhs</c-><c- p>)</c->      <c- o>=</c-> <c- k>default</c-><c- p>;</c->
</pre>
   <p>The allowance for <code class="highlight"><c- n>rhs</c-></code> to be passed by both <code class="highlight"><c- k>const</c-></code> reference and value is consistent with the existing rules for defaulted equality and comparison operators from C++20 (<a href="https://eel.is/c++draft/class.compare.default#1.3">[class.compare.default]</a>).</p>
   <p>Since existing wording for defaulting the copy and move assignment operators explicitly permits them to be lvalue or rvalue qualified (<a href="https://eel.is/c++draft/dcl.fct.def.default#2.1">[dcl.fct.def.default]</a>), for consistency we follow this model and so also tentatively allow the rather arcane:</p>
<pre class="language-cpp highlight"><c- n>A</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>A</c-><c- o>&amp;&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>B</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- n>A</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>A</c-><c- o>&amp;&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>B</c-> <c- n>rhs</c-><c- p>)</c->        <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- n>A</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>A</c-><c- o>&amp;&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>B</c-><c- o>&amp;&amp;</c-> <c- n>rhs</c-><c- p>)</c->      <c- o>=</c-> <c- k>default</c-><c- p>;</c->
</pre>
   <p><a data-link-type="biblio" href="#biblio-p2953" title="Forbid defaulting operator=(X&amp;&amp;) &amp;&amp;">[P2953]</a> seeks to forbid such signatures by requiring that all defaulted assignment operators must operate on an lvalue reference type. For further discussion, see <a href="#others-P2953">§ 6.3 P2953 Forbid defaulting operator=(X&amp;&amp;) &amp;&amp;</a>.</p>
   <p>Regardless, for all signatures above the function body will be equivalent to:</p>
<pre class="language-cpp highlight"><c- p>{</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>lhs</c-><c- p>)</c-> <c- o>+</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>rhs</c-><c- p>);</c->
<c- p>}</c->
</pre>
   <p>though for cases where B is captured by <code class="highlight"><c- k>const</c-><c- o>&amp;</c-></code>, the second move is redundant and so degenerates to</p>
<pre class="language-cpp highlight"><c- p>{</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>lhs</c-><c- p>)</c-> <c- o>+</c-> <c- n>rhs</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Note that we propose to support all ways of expressing such signatures - as traditional member functions, as explicit object functions, or as free functions (declared as friends or directly in the appropriate <code class="highlight"><c- k>namespace</c-></code>). For example, all of the below operations are supported and behave equivalently:</p>
<pre class="language-cpp highlight"><c- k>struct</c-> <c- nc>S1</c-><c- p>{</c->
  <c- b>int</c-> <c- n>value_</c-><c- p>;</c->
  <c- n>S1</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- n>S1</c-> <c- n>rhs</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c-> <c- d>/*...*/</c-> <c- p>}</c->
  <c- n>S1</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>S1</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- p>};</c->

<c- k>struct</c-> <c- nc>S2</c-><c- p>{</c->
  <c- b>int</c-> <c- n>value_</c-><c- p>;</c->
  <c- n>S2</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- n>S2</c-> <c- n>rhs</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c-> <c- d>/*...*/</c-> <c- p>}</c->
  <c- n>S2</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- k>this</c-> <c- n>S2</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>S2</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- p>};</c->

<c- k>struct</c-> <c- nc>S3</c-><c- p>{</c->
  <c- b>int</c-> <c- n>value_</c-><c- p>;</c->
  <c- n>S3</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- n>S3</c-> <c- n>rhs</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c-> <c- d>/*...*/</c-> <c- p>}</c->
<c- p>};</c->
<c- n>S3</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>S3</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>S3</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
</pre>
   <p>Also note that we do not require the underlying operator to be a member function of the class, only that it is visible from the context of the function body of the defaulted compound assignment operator.</p>
   <p>The surrounding rules for the validity of defaulted compound assignment operators is consistent with those for defaulted functions which are already defined in the language, such as the rules specified in <a href="https://eel.is/c++draft/dcl.fct.def.default">[dcl.fct.def.default]</a>, and we shall summarise them here, returning to the example parameter types <code class="highlight"><c- n>A</c-></code> and <code class="highlight"><c- n>B</c-></code> used at the start of this section.</p>
   <p>If the return type of the defaulted compound assignment operator is not <code class="highlight"><c- n>A</c-><c- o>&amp;</c-></code>, or if either <code class="highlight"><c- n>A</c-></code> or <code class="highlight"><c- n>B</c-></code> is not a complete type in the context in which the function is defaulted, the program is ill-formed. If <code class="highlight"><c- n>A</c-></code> is not move-assignable, or if there is no underlying operator with compatible parameter types which is accessible from the context of the body of the defaulted compound operator function, it is defined as deleted. This is consistent with the existing rules for defaulting special member functions.</p>
   <p>We require that the specific overload of the underlying operator which a defaulted compound assignment operator will defer to has a return type of <code class="highlight"><c- n>A</c-></code>, otherwise the function is defined as deleted. This is to ensure that the semantics of the implicitly-generated function body are well-formed and do the right thing. We do not see this as a difficult restriction as it is widely accepted that the default behaviour of <code class="highlight"><c- k>operator</c-><c- o>+</c-></code> is to return a new instance of the same type of its leftmost parameter.</p>
   <h3 class="heading settled" data-level="3.1" id="proposal-edges"><span class="secno">3.1. </span><span class="content">Minor Edge Cases</span><a class="self-link" href="#proposal-edges"></a></h3>
   <p>The behaviour of explicitly defaulted functions is already laid out in the standard, and our design seeks to be as consistent with the existing behaviour as possible. However, there are a few minor edge cases to consider. Our baseline when designing this feature is to consider the case where <code class="highlight"><c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> is replaced with an equivalent function body and to determine whether it results in code which is well-formed and doesn’t exhibit surprising behaviour.</p>
   <h4 class="heading settled" data-level="3.1.1" id="proposal-const"><span class="secno">3.1.1. </span><span class="content">cv-qualification and ref-qualification</span><a class="self-link" href="#proposal-const"></a></h4>
   <p>We forbid a defaulted compound assignment operator from operating on a cv-qualified instance of an object. This is consistent with the existing wording in <a href="https://eel.is/c++draft/class.copy.assign#2">[class.copy.assign]</a> and <a href="https://eel.is/c++draft/dcl.fct.def.default#2">[dcl.fct.def.default]</a> which forbids a defaulted copy- or move-assignment operator from being cv-qualified. We see no good reason to deviate from existing practice.</p>
   <p>While it is in principle possible to engineer a cv-qualified assignment operator overload which in turn would mean that replacing <code class="highlight"><c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> with the canonical function body would produce well-formed code, we do not consider assigning to a <code class="highlight"><c- k>const</c-></code> object as a sensible default for the language. Similarly, we do not permit the rightmost parameter of a defaulted compound assignment operator to be a <code class="highlight"><c- k>volatile</c-></code> reference type. This is not supported by defaulted assignment operators and we do not feel it’s a sensible enough default for compound assignment operators to be treated differently.</p>
   <p>As discussed above, we begrudgingly permit defaulted compound assignment operators to operate on rvalue-ref-qualified types for the sake of consistency. We also note that existing wording for defaulting copy- and move-assignment operators explicitly permits them to be lvalue ref-qualified. As such, the implicit-object non-static member function forms of defaulted compound assignment operator overloads may have any <em>ref-qualifier</em>.</p>
   <h4 class="heading settled" data-level="3.1.2" id="proposal-implicit"><span class="secno">3.1.2. </span><span class="content">Implicit conversion to parameter types of the underlying operator</span><a class="self-link" href="#proposal-implicit"></a></h4>
   
Consider the following code:

<pre class="language-cpp highlight"><c- k>struct</c-> <c- nc>from_int</c-><c- p>{</c->
    <c- n>from_int</c-><c- p>(</c-><c- b>int</c-><c- p>)</c-> <c- p>{}</c-> <c- c1>//implicitly constructible from int</c->
<c- p>};</c->
<c- n>foo</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- n>foo</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>from_int</c-> <c- n>rhs</c-><c- p>){</c-> <c- d>/* ... */</c-><c- p>}</c->
<c- n>foo</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>foo</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- b>int</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
</pre>
   <p>Should this defaulted <code class="highlight"><c- k>operator</c-><c- o>+=</c-></code> overload be permitted? If we were to directly replace <code class="highlight"><c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> with the canonical function body then the implicit conversion of <code class="highlight"><c- n>rhs</c-></code> to <code class="highlight"><c- n>from_int</c-></code> would trigger and the code would work. However, allowing such implicit conversions inside a generated function body also has the potential to increase user confusion by permitting an unexpected overload of the underlying binary operator to be called. We note that the scope of this proposal covers the bitwise operators, which are frequently overloaded to perform operations other than bit manipulation, and this could lead to potentially surprising conversion paths.</p>
   <p>On the other hand, having the above code be ill-formed or the overload defined as deleted because an implicit conversion would happen inside of a function body that doesn’t exist in the user’s code would be a very surprising and confusing bug. While it is arguable that an implicit conversion bug may be more surprising, we see this as a symptom of user code allowing undesirable implicit conversion paths rather than a defect in the concept of defaulting compound assignment operators. Similarly, making such function calls ill-formed would come with its own complexities; such as users attempting to SFINAE on the validity of such declarations. While it would certainly be possible to engineer user-hostile conversion paths if we permit the above code, we do not consider it likely in reasonable code. We expect that by far the most likely use of this proposal is that users will naturally match the parameter types between their defaulted compound assignment operators and their existing underlying operator overloads as is the common default today.</p>
   <p>Considering this, we only require that there exists an underlying operator overload which would be callable if <code class="highlight"><c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> were replaced by its canonical function body; not that all parameter types must match exactly.</p>
   <h4 class="heading settled" data-level="3.1.3" id="proposal-xobj-type"><span class="secno">3.1.3. </span><span class="content">Explicit object parameter types</span><a class="self-link" href="#proposal-xobj-type"></a></h4>
   
We require that an explicit object parameter of a defaulted compound assignment operator must be of the same type of the class in which it is declared, and note that existing wording in <a href="https://eel.is/c++draft/dcl.fct.def.default#2.2">[dcl.fct.def.default]</a> already enforces this for other defaulted functions.


   <h4 class="heading settled" data-level="3.1.4" id="proposal-self-assignment"><span class="secno">3.1.4. </span><span class="content">Self-assignment</span><a class="self-link" href="#proposal-self-assignment"></a></h4>
   
We do not see the need to insert a check for self-assignment in a defaulted compound assignment operation. Our requirement that the underlying operator’s return type be by value means that we will always be assigning from a brand new instance of the class, and in the unlikely case that there is potential breakage in either assignment from a different instance or calls to the underlying operator with the same object twice, these must already be handled inside their respective functions.



   <h3 class="heading settled" data-level="3.2" id="proposal-function-body"><span class="secno">3.2. </span><span class="content"><code class="highlight"><c- o>=</c-> <c- k>default</c-></code> is a function body</span><a class="self-link" href="#proposal-function-body"></a></h3>
   <p>We note specifically that <code class="highlight"><c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> is a <em>function-body</em> which the implementation uses to inject the canonical semantics for that function. As such, declaration-level grammar of explicitly defaulted functions is unaffected. The declaration of an explicitly defaulted function may still be marked <code class="highlight"><c- k>noexcept</c-></code> or <code class="highlight"><c- k>constexpr</c-></code>, it may still be constrained with <code class="highlight"><c- k>requires</c-></code> clauses or have attributes appertaining to it.</p>
   <p>Consequently, this paper neither forbids nor requires further grammar changes to permit code such as:</p>
<pre class="language-cpp highlight"><c- k>class</c-> <c- nc>foo</c-><c- p>{</c-> <c- d>/*...*/</c-> <c- p>};</c->
<c- k>constexpr</c-> <c- n>foo</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->
<c- k>constexpr</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>foo</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-><c- p>)</c-> <c- k>noexcept</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
</pre>
   <p>Similarly, there is no magic associated with <code class="highlight"><c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> which affects overload resolution.  No part of this proposal permits the implicit creation of the operator signatures we are discussing: users must explicitly opt-in. Nor should there be any surprises in overload resolution order. And, while it is not necessary, if the user wishes to explicitly delete their compound assignment operator overloads then no part of this proposal prevents them from doing so.</p>
   <p>This also means it is possible for the user to declare multiple defaulted compound assignment operator overloads for a given class, provided that they would otherwise be valid overloads:</p>
<pre class="language-cpp highlight"><c- k>class</c-> <c- nc>bar</c-><c- p>{</c-> <c- d>/*...*/</c-> <c- p>};</c->
<c- n>bar</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- k>const</c-> <c- n>bar</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>bar</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>);</c->
<c- n>bar</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- k>const</c-> <c- n>bar</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>bar</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
<c- n>bar</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- k>const</c-> <c- n>bar</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>bar</c-><c- o>&amp;&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->

<c- n>bar</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- k>const</c-> <c- n>bar</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- b>int</c-> <c- n>rhs</c-><c- p>);</c->
<c- n>bar</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- k>const</c-> <c- n>bar</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- b>int</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
</pre>
   <h2 class="heading settled" data-level="4" id="boilerplate"><span class="secno">4. </span><span class="content">Are We Creating Tomorrow’s Boilerplate?</span><a class="self-link" href="#boilerplate"></a></h2>
   <p>It is easy to imagine a world where a class contains many defaulted functions and operators. Consider:</p>
<pre class="language-cpp highlight"><c- k>class</c-> <c- nc>foo</c-><c- p>{</c->
  <c- n>some_data</c-> <c- n>m_data</c-><c- p>;</c->

  <c- k>public</c-><c- o>:</c->

  <c- c1>//C++11</c->
  <c- n>foo</c-><c- p>()</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
  <c- n>foo</c-><c- p>(</c-><c- n>bar</c-><c- p>){</c-> <c- p>...</c-> <c- p>}</c->


  <c- c1>//C++20</c->
  <c- k>auto</c-> <c- k>operator</c-><c- o>&lt;=></c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-><c- p>)</c-> <c- k>const</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->

  <c- c1>//P3668</c->
  <c- n>foo</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>++</c-><c- p>()</c-> <c- p>{</c-> <c- p>...</c-> <c- p>}</c->
  <c- n>foo</c-> <c- k>operator</c-><c- o>++</c-><c- p>(</c-><c- b>int</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
  <c- n>foo</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>--</c-><c- p>()</c-> <c- p>{</c-> <c- p>...</c-> <c- p>}</c->
  <c- n>foo</c-> <c- k>operator</c-><c- o>--</c-><c- p>(</c-><c- b>int</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->

  <c- c1>//This proposal</c->
  <c- n>foo</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c-> <c- p>...</c-> <c- p>}</c->
  <c- n>foo</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
  <c- n>foo</c-> <c- k>operator</c-><c- o>-</c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c-> <c- p>...</c-> <c- p>}</c-> 
  <c- n>foo</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>-=</c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->

<c- p>};</c->
</pre>
   <p>It’s reasonable to ask whether this reduction in boilerplate itself creates boilerplate which would need to be reduced in future. We consider it preferable for the operations on a class to be explicitly visible in code, and EWG has previously found consensus in agreement (<a data-link-type="biblio" href="#biblio-p1046-ewg" title="EWG comments from the Belfast meeting">[P1046-EWG]</a>). We argue that reducing it further would violate our second design principle by requiring the user to deduce supported operations rather than simply read them. Ultimately, we don’t see this boilerplate as a symptom of a problem with the proposal but just a consequence of the fact that C++ requires a certain level of verbosity when describing a class' supported features. This is not unique to C++ - we also note that an equivalent class in Python, using its dunder methods for supported operations, would have a similar line count.</p>
   <p>Further discussion on issues with implicit generation of operators can be found in <a href="#alternatives-rewrite">§ 5.6 Rewrite Rule and Implicit Generation of Operators</a>.</p>
   <h2 class="heading settled" data-level="5" id="alternatives"><span class="secno">5. </span><span class="content">Alternatives Considered</span><a class="self-link" href="#alternatives"></a></h2>
   <h3 class="heading settled" data-level="5.1" id="proposal-plus-equals"><span class="secno">5.1. </span><span class="content">Defining <code class="highlight"><c- k>operator</c-><c- o>+</c-></code> in terms of <code class="highlight"><c- k>operator</c-><c- o>+=</c-></code></span><a class="self-link" href="#proposal-plus-equals"></a></h3>
   <p>There has historically been some discussion in C++ about whether it is better to implement the compound assignment operator in terms of its underlying operator:</p>
<pre class="language-cpp highlight"><c- k>struct</c-> <c- nc>foo</c-><c- p>{</c-><c- b>int</c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>;};</c->
<c- n>foo</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>){</c->
    <c- k>return</c-> <c- n>foo</c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>x</c-> <c- o>+</c-> <c- n>rhs</c-><c- p>.</c-><c- n>x</c-><c- p>,</c-> <c- n>lhs</c-><c- p>.</c-><c- n>y</c-> <c- o>+</c-> <c- n>rhs</c-><c- p>.</c-><c- n>y</c-><c- p>};</c->
<c- p>}</c->
<c- n>foo</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>foo</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>){</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>=</c-> <c- n>lhs</c-> <c- o>+</c-> <c- n>rhs</c-><c- p>;</c-> 
<c- p>}</c->
</pre>
   <p>or to do the reverse:</p>
<pre class="language-cpp highlight"><c- k>struct</c-> <c- nc>foo</c-><c- p>{</c-><c- b>int</c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>;};</c->
<c- n>foo</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>foo</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>){</c->
    <c- n>lhs</c-><c- p>.</c-><c- n>x</c-> <c- o>+=</c-> <c- n>rhs</c-><c- p>.</c-><c- n>x</c-><c- p>;</c->
    <c- n>rhs</c-><c- p>.</c-><c- n>y</c-> <c- o>+=</c-> <c- n>rhs</c-><c- p>.</c-><c- n>y</c->
    <c- k>return</c-> <c- n>lhs</c-><c- p>;</c->
<c- p>}</c->
<c- n>foo</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- n>foo</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>){</c->
    <c- k>return</c-> <c- n>lhs</c-> <c- o>+=</c-> <c- n>rhs</c-><c- p>;</c-> 
<c- p>}</c->
</pre>
   <p>As such, it is reasonable to ask whether we should permit defaulting the underlying operator instead of, or in addition to, the compound assignment operator.</p>
   <p>We argue that this would be a misstep. From first principles it makes far more sense to default the composition of <code class="highlight"><c- o>+</c-></code> and <code class="highlight"><c- o>=</c-></code> than it does to require the user define the composite operation in order to generate the behaviour of one of the elementary operations. Defaulting the underlying operator comes with additional potential for confusion, for example a user might have trouble intuiting that <code class="highlight"><c- n>foo</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-><c- p>,</c-> <c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> is a function which implicitly calls <code class="highlight"><c- k>operator</c-><c- o>+=</c-></code> to perform addition as opposed to some other purpose (e.g. memberwise addition for aggregates).</p>
   <p>The possibility of defaulting both operator categories also comes with many issues. First and foremost, checking for the validity of a defaulted operation becomes significantly harder if either the compound assignment operator and the underlying operator may be defaulted. Similarly, it opens up a difficult question on what to do if both are defaulted. It occupies twice as much syntactic space and is harder to reason about than simply defaulting the compound operators. It opens the door to lengthy discussions about which is the better operator to default and how that may differ from handwritten operators.</p>
   <p>David Stone explores this same question in <a data-link-type="biblio" href="#biblio-p1046" title="Automatically Generate More Operators">[P1046]</a>, and writes:</p>
   <blockquote>
    
One interesting thing of note here is that the operator+= implementation does not know anything about its types other than that they are addable and assignable. Compare that with the operator+ implementations from the first piece of code where they need to know about sizes, reserving, and insertion because operator+= alone is not powerful enough. There are several more counterexamples that argue against operator+= being our basis operation, but most come down to the same fact: operator+ does not treat either argument -- lhs or rhs -- specially, but operator+= does.


    <p>The first counterexample is std::string (again). We can perform <code class="highlight"><c- n>string</c-> <c- o>+=</c-> <c- n>string_view</c-></code>, but not <code class="highlight"><c- n>string_view</c-> <c- o>+=</c-> <c- n>string</c-></code>. If we try to define operator+ in terms of operator+=, that would imply that we would be able to write <code class="highlight"><c- n>string</c-> <c- o>+</c-> <c- n>string_view</c-></code>, but not <code class="highlight"><c- n>string_view</c-> <c- o>+</c-> <c- n>string</c-></code>, which seems like an odd restriction. The class designer would have to manually write out both += and +, defeating our entire purpose.</p>
    <p>The second counterexample is the <code class="highlight"><c- n>bounded</c-><c- o>::</c-><c- n>integer</c-></code> library and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>chrono</c-><c- o>::</c-><c- n>duration</c-></code>. <code class="highlight"><c- n>bounded</c-><c- o>::</c-><c- n>integer</c-></code> allows users to specify compile-time bounds on an integer type, and the result of arithmetic operations reflects the new bounds based on that operation. For instance, <code class="highlight"><c- n>bounded</c-><c- o>::</c-><c- n>integer</c-><c- o>&lt;</c-><c- mi>0</c-><c- p>,</c-> <c- mi>10</c-><c- o>></c-> <c- o>+</c-> <c- n>bounded</c-><c- o>::</c-><c- n>integer</c-><c- o>&lt;</c-><c- mi>1</c-><c- p>,</c-> <c- mi>9</c-><c- o>></c-> <c- o>=></c-> <c- n>bounded</c-><c- o>::</c-><c- n>integer</c-><c- o>&lt;</c-><c- mi>1</c-><c- p>,</c-> <c- mi>19</c-><c- o>></c-></code>. <code class="highlight"><c- n>duration</c-><c- o>&lt;</c-><c- n>LR</c-><c- p>,</c-> <c- n>Period</c-><c- o>></c-> <c- o>+</c-> <c- n>duration</c-><c- o>&lt;</c-><c- n>RR</c-><c- p>,</c-> <c- n>Period</c-><c- o>></c-> <c- o>=></c-> <c- n>duration</c-><c- o>&lt;</c-><c- n>common_type_t</c-><c- o>&lt;</c-><c- n>LR</c-><c- p>,</c-> <c- n>RR</c-><c- o>></c-><c- p>,</c-> <c- n>Period</c-><c- o>></c-></code> If operator+= is the basis, it requires that the return type of the operation is the same as the type of the left-hand side of that operation. This is fundamentally another instance of the same problem with <code class="highlight"><c- n>string_view</c-> <c- o>+</c-> <c- n>string</c-></code>.</p>
    <p>The third counterexample is all types that are not assignable (for instance, if they contain a const data member). This restriction makes sense conceptually. An implementation of operator+ requires only that the type is addable in some way. Thanks to guaranteed copy elision, we can implement it on most types in such a way that we do not even require a move constructor. An implementation of operator+= requires that the type is both addable and assignable. We should make the operations with the broadest applicability our basis.</p>
   </blockquote>
   <p>Overall, we argue that the only sensible option to default are the compound assignment operators, and while there have historically been some benefits to implementing <code class="highlight"><c- k>operator</c-><c- o>+</c-></code> in terms of <code class="highlight"><c- k>operator</c-><c- o>+=</c-></code> they do not outweigh the issues which defaulting the underlying operator in terms of its compound assignment operator would bring.</p>
   <h3 class="heading settled" data-level="5.2" id="alternatives-forwarding"><span class="secno">5.2. </span><span class="content">A Perfect Forwarding Compound Assignment Operator Template</span><a class="self-link" href="#alternatives-forwarding"></a></h3>
   <p>Given that our proposal requires users to place two declarations of a compound operator in their class if they want to support the rightmost argument being copied or moved as appropriate into the underlying operator function, it may be tempting to propose supporting the ability to default an operator overload function template, which forwards the argument. For example:</p>
<pre class="language-cpp highlight"><c- n>A</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>A</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>convertible_to</c-><c- o>&lt;</c-><c- n>B</c-><c- o>></c-> <c- k>auto</c-><c- o>&amp;&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c->
</pre>
   <p>While we agree this looks good at first pass, it opens the door to a lot of issues in terms of semantics and consistency with the rest of the language. Nowhere else in the language are explicitly defaulted functions permitted to be function templates, so permitting them here would be an inconsistency. Equally, it raises a question of whether we should only permit the above signature or whether any valid function template signature should be defaultable. We argue that defaulting function templates is a separate proposal with its own open design questions to consider and should not be considered as a requirement for this proposal. Similarly, we are not entirely persuaded that a perfect forwarding template is used as a common sensible default in real code.</p>
   <h3 class="heading settled" data-level="5.3" id="alternatives-dynamite"><span class="secno">5.3. </span><span class="content">A Magic Pseudo Operator</span><a class="self-link" href="#alternatives-dynamite"></a></h3>
   
One idea which has occasionally been discussed is to introduce some "magic" pseudo operator which when defaulted in a class implicitly adds all generatable operators to it, for example:


<pre class="language-cpp highlight"><c- k>class</c-> <c- nc>foo</c-><c- p>{</c->
    <c- n>foo</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c-> <c- d>/*...*/</c-> <c- p>}</c->
    <c- n>foo</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>-=</c-><c- p>(</c-><c- k>const</c-> <c- n>foo</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- p>{</c-> <c- d>/*...*/</c-> <c- p>}</c->

    <c- k>auto</c-> <c- k>operator</c->@<c- o>=</c-><c- p>()</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c-> <c- c1>//Implicitly adds operator+= and operator- to the class</c->
<c- p>};</c->
</pre>
   <p>We think this is a little too cute, and do not prefer it to explicitly defaulting the compound operators. Defining a construct which looks like an operator but is a handle on some internal function injection could be very confusing for users. There are difficult questions about how the function semantics of <code class="highlight"><c- k>operator</c->@<c- o>=</c-></code> should be specified - for example what return type it should claim to have, what parameters it should accept, and whether it is considered to be acting on <code class="highlight"><c- k>const</c-></code> or mutable instances of the class. Equally it could not be constrained to being an apparent nonstatic member function - there are good reasons users might have to define their operator overloads as free functions and <code class="highlight"><c- k>operator</c->@<c- o>=</c-></code> would have to be a free function itself in order to be able to see them and generate code accordingly. This raises additional points of confusion if some operators are defined in a different TU from <code class="highlight"><c- k>operator</c->@<c- o>=</c-></code> and so cannot have their counterparts generated, and whether multiple "definitions" of <code class="highlight"><c- k>operator</c->@<c- o>=</c-></code> should be permitted.</p>
   <p>What such a pseudo operator attempts to achieve is to give the user some declaration they can insert into a class to say "give me the default operations"; but C++ already has such a declaration with <code class="highlight"><c- o>=</c-> <c- k>default</c-></code> and we are not persuaded that an additional one would be an improvement. Overall we do not consider this a workable idea for the language.</p>
   <h3 class="heading settled" data-level="5.4" id="alternatives-reflection"><span class="secno">5.4. </span><span class="content">Reflection Solutions</span><a class="self-link" href="#alternatives-reflection"></a></h3>
   <p>When generative reflection arrives, it is conceivable that it would be possible to write some <code class="highlight"><c- n>add_generatable_operators</c-><c- p>()</c-></code> metafunction which reads the valid operations for some class and generates the "default" behaviour of any others based on them. We agree, and do not see this proposal as competing with reflection in that space. Indeed, the ability to simply inject <code class="highlight"><c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> as the function body could make such a metafunction far easier to write.</p>
   <p>However, we also hold that such a metafunction would be a poor candidate for standardisation. There are many possibly generatable operators following many different possible paths - not just through operators which can be defaulted but also through compositions of other operators, such as obtaining subtraction through addition and unary negation, or other compositions such as those explored in <a data-link-type="biblio" href="#biblio-p1046" title="Automatically Generate More Operators">[P1046]</a>. It is not clear what the scope of a "standard" metafunction to do this should be; nor is it clear whether it should be expanded if new operators or operator generation methods are added in future standards.</p>
   <p>It is also conceivable that metafunctions can be written to add each generatable operator in turn, or each family of operators. We see this as a standardisation issue in itself - a monolith of standard metafunctions for specific cases is not desirable, and it may not be easy to agree on which families of operators should be grouped together. This aside, however, we do not find that these solutions are as easily readable as simply defaulting the operators. The code to generate these is complex, and the mechanism to inject them may not be immediately clear to non-expert C++ developers. Consider this example from Matthias Wippich, following the design laid out in <a data-link-type="biblio" href="#biblio-p3294" title="Code Injection with Token Sequences">[P3294]</a>:</p>
<pre class="language-cpp highlight"><c- cp>#include</c-> &lt;experimental/meta>

<c- k>consteval</c-> <c- b>void</c-> <c- nf>generate_arithmetic</c-><c- p>(</c-><c- n>std</c-><c- o>::</c-><c- n>meta</c-><c- o>::</c-><c- n>info</c-> <c- n>R</c-><c- p>)</c-> <c- p>{</c->
  <c- c1>// note that is_incomplete_type got replaced with is_complete_type</c->
  <c- k>auto</c-> <c- n>befriend</c-> <c- o>=</c-> <c- n>is_incomplete_type</c-><c- p>(</c-><c- n>R</c-><c- p>)</c-> <c- o>?</c-> <c- o>^^</c-><c- p>{</c-><c- k>friend</c-><c- p>}</c-> <c- o>:</c-> <c- o>^^</c-><c- p>{};</c->
  <c- k>auto</c-> <c- n>inject</c-> <c- o>=</c-> <c- p>[</c-><c- o>&amp;</c-><c- p>](</c-><c- n>std</c-><c- o>::</c-><c- n>meta</c-><c- o>::</c-><c- n>info</c-> <c- n>op</c-><c- p>,</c-> <c- n>std</c-><c- o>::</c-><c- n>meta</c-><c- o>::</c-><c- n>info</c-> <c- n>rewritten</c-><c- p>)</c-> <c- p>{</c->
    <c- k>auto</c-> <c- n>tokens</c-> <c- o>=</c-> <c- o>^^</c-><c- p>{</c->
      <c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- nc>U</c-><c- o>></c->
      \<c- n>tokens</c-><c- p>(</c-><c- n>befriend</c-><c- p>)</c-> <c- k>typename</c-><c- p>[</c-><c- o>:</c->\<c- p>(</c-><c- n>R</c-><c- p>)</c-><c- o>:</c-><c- p>]</c-><c- o>&amp;</c-> \<c- n>tokens</c-><c- p>(</c-><c- n>rewritten</c-><c- p>)(</c-><c- k>typename</c-><c- p>[</c-><c- o>:</c->\<c- p>(</c-><c- n>R</c-><c- p>)</c-><c- o>:</c-><c- p>]</c-><c- o>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- n>U</c-><c- o>&amp;&amp;</c-> <c- n>rhs</c-><c- p>)</c-> 
        <c- k>requires</c-> <c- k>requires</c-> <c- p>{</c-> 
          <c- p>{</c-> <c- n>lhs</c-> \<c- n>tokens</c-><c- p>(</c-><c- n>op</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>U</c-><c- o>></c-><c- p>(</c-><c- n>rhs</c-><c- p>)</c-> <c- p>};</c->
        <c- p>}</c->
      <c- p>{</c->
        <c- n>lhs</c-> <c- o>=</c-> <c- n>std</c-><c- o>::</c-><c- n>move</c-><c- p>(</c-><c- n>lhs</c-><c- p>)</c-> \<c- n>tokens</c-><c- p>(</c-><c- n>op</c-><c- p>)</c-> <c- n>std</c-><c- o>::</c-><c- n>forward</c-><c- o>&lt;</c-><c- n>U</c-><c- o>></c-><c- p>(</c-><c- n>rhs</c-><c- p>);</c->
        <c- k>return</c-> <c- n>lhs</c-><c- p>;</c->
      <c- p>}</c->
    <c- p>};</c->
    <c- n>queue_injection</c-><c- p>(</c-><c- n>tokens</c-><c- p>);</c->
  <c- p>};</c->

  <c- n>inject</c-><c- p>(</c-><c- o>^^</c-><c- p>{</c-><c- o>+</c-><c- p>},</c-> <c- o>^^</c-><c- p>{</c-><c- k>operator</c-><c- o>+=</c-><c- p>});</c->
  <c- n>inject</c-><c- p>(</c-><c- o>^^</c-><c- p>{</c-><c- o>-</c-><c- p>},</c-> <c- o>^^</c-><c- p>{</c-><c- k>operator</c-><c- o>-=</c-><c- p>});</c->
<c- p>}</c->



<c- c1>// USAGE</c->
<c- k>struct</c-> <c- nc>Vec2</c-> <c- p>{</c->
  <c- b>float</c-> <c- n>x</c-><c- p>,</c-> <c- n>y</c-><c- p>;</c->
  <c- n>Vec2</c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- n>Vec2</c-> <c- k>const</c-><c- o>&amp;</c-> <c- n>other</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- p>{</c-><c- n>x</c-> <c- o>+</c-> <c- n>other</c-><c- p>.</c-><c- n>x</c-><c- p>,</c-> <c- n>y</c-> <c- o>+</c-> <c- n>other</c-><c- p>.</c-><c- n>y</c-><c- p>};</c-> <c- p>}</c->
  <c- n>Vec2</c-> <c- k>operator</c-><c- o>-</c-><c- p>(</c-><c- n>Vec2</c-> <c- k>const</c-><c- o>&amp;</c-> <c- n>other</c-><c- p>)</c-> <c- k>const</c-> <c- p>{</c-> <c- k>return</c-> <c- p>{</c-><c- n>x</c-> <c- o>-</c-> <c- n>other</c-><c- p>.</c-><c- n>x</c-><c- p>,</c-> <c- n>y</c-> <c- o>-</c-> <c- n>other</c-><c- p>.</c-><c- n>y</c-><c- p>};</c-> <c- p>}</c->

  <c- k>consteval</c-> <c- p>{</c-> <c- n>generate_arithmetic</c-><c- p>(</c-><c- o>^^</c-><c- n>Vec2</c-><c- p>);</c-> <c- p>}</c->
<c- p>};</c->

<c- b>int</c-> <c- nf>main</c-><c- p>()</c-> <c- p>{</c->
  <c- n>Vec2</c-> <c- n>a</c-><c- p>{</c-><c- mi>1</c-><c- p>,</c-> <c- mi>2</c-><c- p>},</c-> <c- n>b</c-><c- p>{</c-><c- mi>3</c-><c- p>,</c-> <c- mi>4</c-><c- p>};</c->
  <c- n>a</c-> <c- o>+=</c-> <c- n>b</c-><c- p>;</c->
  <c- n>a</c-> <c- o>-=</c-> <c- n>b</c-><c- p>;</c->
<c- p>}</c->

</pre>
   <p><a href="https://godbolt.org/z/P5r89cxTv">Godbolt here</a></p>
   <p>This code is a complex way of achieving the same overall effect as defaulting these operators. Additionally, the call to <code class="highlight"><c- n>generate_arithmetic</c-></code> is a different shape from common declarations; and may not be easily coupled with the class definition. We are not convinced that the above code should be a common pattern to solve everyday code problems - it is far easier to understand the operations which a class supports by reading function declarations than it is to parse each <code class="highlight"><c- k>consteval</c-></code> block and mentally unwrap an opaque function call to some reflection function. A user may also declare their underlying operators as free functions, which means that the <code class="highlight"><c- k>consteval</c-></code> block may exist outside of the class definition in order to be able to see the supported operations. This in turn makes the injection function more error-prone and we argue that injection functions which are so decoupled from the definitions of the classes on which they operate are far harder to reason about than a defaulted function declaration.</p>
   <p>We hold that while such a reflection based solution may be of use for specific situations and specific users, it does not mean that we cannot recognise the canonical default behaviour of these functions by defaulting them as a more general-purpose solution.</p>
   <h3 class="heading settled" data-level="5.5" id="alternatives-free-functions"><span class="secno">5.5. </span><span class="content">Free Function Compound Assignment Operator Templates</span><a class="self-link" href="#alternatives-free-functions"></a></h3>
   <p>It would be possible to define some global operator templates to support compound assignment, which are made opt-in by some template bool <code class="highlight"><c- n>enable_compound_addition</c-></code> or some <code class="highlight"><c- p>[[</c-><c- o>=</c-><c- n>generate_compounds</c-><c- p>]]</c-></code> annotation. This has similar problems to other reflection-based solutions - the granularity of the opt-in switch is difficult to determine and the operations which a class supports become harder to reason about as the user must go hunting for the special tag which describes functionality rather than traditional function declarations. Such a solution comes with additional problems - free function templates may not be generated if the user intends for an implicit conversion to occur.</p>
   <p>Consider the classic example where implicit conversions fail for the left argument of a binary operator:</p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
<c- k>class</c-> <c- nc>wrap</c-><c- p>{</c->
    <c- n>T</c-> <c- n>t_</c-><c- p>;</c-> 

    <c- k>public</c-><c- o>:</c->
    <c- n>wrap</c-><c- p>(</c-><c- k>const</c-> <c- n>T</c-><c- o>&amp;</c-> <c- n>value</c-><c- p>)</c-> <c- o>:</c-> <c- n>t_</c-><c- p>{</c-><c- n>value</c-><c- p>}</c-> <c- p>{}</c-> <c- c1>//Implicitly constructible from T</c->

    <c- k>auto</c-><c- o>&amp;</c-> <c- n>get</c-><c- p>(</c-><c- k>this</c-> <c- k>auto</c-><c- o>&amp;&amp;</c-> <c- n>self</c-><c- p>){</c->
        <c- k>return</c-> <c- n>self</c-><c- p>.</c-><c- n>t_</c-><c- p>;</c->
    <c- p>}</c->
<c- p>};</c->

<c- k>template</c-><c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
<c- n>wrap</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-> <c- k>operator</c-><c- o>+</c-><c- p>(</c-><c- k>const</c-> <c- n>wrap</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>wrap</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>&amp;</c-> <c- n>rhs</c-><c- p>){</c->
    <c- k>return</c-> <c- n>wrap</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c-><c- p>{</c-><c- n>lhs</c-><c- p>.</c-><c- n>get</c-><c- p>()</c-> <c- o>+</c-> <c- n>rhs</c-><c- p>.</c-><c- n>get</c-><c- p>()};</c->
<c- p>}</c->

<c- b>int</c-> <c- n>main</c-><c- p>(){</c->
    <c- n>wrap</c-><c- o>&lt;</c-><c- b>int</c-><c- o>></c-> <c- n>wr</c-><c- p>{</c-><c- mi>0</c-><c- p>};</c->
    <c- mi>0</c-> <c- o>+</c-> <c- n>wr</c-><c- p>;</c-> <c- c1>//Ill-formed: No match for operator+</c->
<c- p>}</c->
</pre>
   <p>The traditional solution to this problem is to declare <code class="highlight"><c- k>operator</c-><c- o>+</c-></code> as a hidden friend, but this would not be possible to do for the default compound operators if they were free functions in some header.</p>
   <p>We argue that putting function templates for supported operations into standard library headers makes code harder to reason about, not easier. These definitions would not be local to the class in code, would require memorising the special rule that X tag means Y behaviour, and too closely resembles <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>rel_ops</c-></code>. The idea was dropped.</p>
   <h3 class="heading settled" data-level="5.6" id="alternatives-rewrite"><span class="secno">5.6. </span><span class="content">Rewrite Rule and Implicit Generation of Operators</span><a class="self-link" href="#alternatives-rewrite"></a></h3>
   <p>At first glance, it may seem tempting to permit a spacehip operator-style rewrite rule of <code class="highlight"><c- n>a</c-> <c- o>+=</c-> <c- n>b</c-></code> to <code class="highlight"><c- n>a</c-> <c- o>=</c-> <c- n>a</c-> <c- o>+</c-> <c- n>b</c-></code>. However this comes with many potential traps and sources of confusion. We maintain that it is preferable for a class' supported operations to be visible in code, and that implicit generation of supported operations is harder to reason about than the status quo in this case. There are additional concerns - a rewrite rule following current C++ convention would be forced to evaluate <code class="highlight"><c- n>a</c-></code> twice when rewritten rather than just once. If <code class="highlight"><c- n>a</c-></code> were the result of some function call <code class="highlight"><c- n>f</c-><c- p>()</c-></code>, then the function would be called a second time implicitly, which would at the very least be surprising. We can only see two possibilities to avoid this while maintaining rewrite. The first is a carveout in the wording to make such rewrites "magic" in only evaluating the left operand once, and we do not believe that the complexity of this special case justifies its benefits. The second is to have the call to <code class="highlight"><c- n>a</c-> <c- o>+=</c-> <c- n>b</c-></code> crystalise some implicit actual function or function object such that <code class="highlight"><c- n>a</c-></code> is only evaluated once as it is bound to a parameter or variable. We do not think that this is a viable path either, as introducing a second mechanism by which rewrite rules work makes an already complex topic significantly harder to reason about and remember. It introduces ODR issues in and of itself if such an operator is generated in a header; but also if the user attempts to declare a traditional operator overload after the implicit one has been generated.</p>
   <p>Such a change would come with a specification burden to other papers. Consider the <code class="highlight"><c- n>declcall</c-></code> operator as proposed by <a data-link-type="biblio" href="#biblio-p2825" title="Overload resolution hook: declcall( unevaluated-call-expression )">[P2825]</a>. Should <code class="highlight"><c- n>declcall</c-><c- p>(</c-><c- n>a</c-> <c- o>+=</c-> <c- n>b</c-><c- p>)</c-></code> be well-formed if used in a translation unit where the compiler has not generated an implicit function to perform the operation? The call to <code class="highlight"><c- n>a</c-> <c- o>+=</c-> <c- n>b</c-></code> at that place in code would itself be well-formed and call some kind of function, but the dedicated tool to reach that function may have to be conditionally ill-formed depending on what code already exists in the current translation unit. Should such an implicitly generated function be a reflectable member of whatever namespace it is considered to be declared in? Must users explicitly generate these functions with a series of <code class="highlight"><c- n>a</c-> <c- o>+=</c-> <c- n>b</c-></code>, <code class="highlight"><c- n>a</c-> <c- o>-=</c-> <c- n>b</c-></code>, <code class="highlight"><c- n>a</c-> <c- o>*=</c-> <c- n>b</c-></code>, and so on before they are reflectable? Or should we be able to reflect on all possible <em>potential</em> functions which would be possible to generate and use in user code at that point in that TU? A reflection of something which does not exist in source code seems quesitonable, but so does the inability to reflect on all of a class' supported operations.</p>
   <p>An alternative path we could take would be to follow the approach of the special member functions with operations which are implicitly present even if not user-declared. For example, we could propose that following the declaration of an underlying operator, that there implicitly is a compound assignment operator present in the same way that a class' move-assignment operator is implicitly present. This would solve some of the above issues - user level declarations of a given compound assignment operator overload would not conflict with the implicit one - they would instead be considered to work similarly to a user-provided special member function and subsume it. But it comes with many issues of its own. The special member functions are required to be member functions of their classes for good reason, whereas compound assignment operations may be free functions and as such may exist anywhere in code. We do not think it is reasonable for compilers or for users to reason about potentially-non-default implicit operator declarations which may be present anywhere in the current TU. The existing implicit presence of special member functions has historically been a cause of confusion and difficulty for beginners; and we don’t see this idea as less confusing. Equally, this design shares issues with rewrite rules and implicit generation of operation overloads in general - it is opt-out, rather than opt-in. Existing code which made the decision to not support compound assignment operations must be updated with explicitly deleted function overloads in order to maintain this decision, otherwise code which is ill-formed today would become code which is well-formed but does the wrong thing.</p>
   <p>Overall we are not convinced that a rewrite rule is the best design, nor is it practically feasible, so the idea was dropped.</p>
   <h2 class="heading settled" data-level="6" id="Other-papers"><span class="secno">6. </span><span class="content">Other Papers in this Space</span><a class="self-link" href="#Other-papers"></a></h2>
   <p>We are not aware of any other active papers which seek to automatically generate compound assignment operator overloads, however there are some papers which occupy the more general space of explicitly defaulted functions, and we note them here:</p>
   <h3 class="heading settled" data-level="6.1" id="others-P1046"><span class="secno">6.1. </span><span class="content">P1046 Automatically Generate More Operators</span><a class="self-link" href="#others-P1046"></a></h3>
   
<a data-link-type="biblio" href="#biblio-p1046" title="Automatically Generate More Operators">[P1046]</a> sought to add additional rewrite rules to the language, following the pattern of the spaceship operator in C++20, and this included rewriting the compound assignment operators into some composition of the underlying operator and assignment operator. P1046 is currently parked in favor of a more fine-grained proposal <a data-link-type="biblio" href="#biblio-p3039" title="Automatically Generate operator->">[P3039]</a>, which does not overlap with this paper.


   <h3 class="heading settled" data-level="6.2" id="others-P2952"><span class="secno">6.2. </span><span class="content">P2952 auto&amp; operator=(X&amp;&amp;) = default;</span><a class="self-link" href="#others-P2952"></a></h3>
   
<a data-link-type="biblio" href="#biblio-p2952" title="auto&amp; operator=(X&amp;&amp;) = default">[P2952]</a> argues that explicitly defaulted functions should be permitted to use placeholder types in their return types, so long as the chosen placeholder type would deduce to the correct return type if the return statement in the canonical function body were present. For example, <code class="highlight"><c- k>operator</c-><c- o>==</c-></code> is permitted to use <code class="highlight"><c- k>auto</c-></code> but not <code class="highlight"><c- k>auto</c-><c- o>&amp;</c-></code> or <code class="highlight"><c- k>auto</c-><c- o>*</c-></code> as its declared return type.


   <p>This paper is compatible with P2952, and as defaulted compound assignment operators much always have a return type of <code class="highlight"><c- n>A</c-><c- o>&amp;</c-></code>, they follow the same placeholder return type pattern as defaulted copy- and move-assignment operators:</p>
   <div class="example" id="example-43462e4a">
    <a class="self-link" href="#example-43462e4a"></a>
  
    <p>
    The behaviour of placeholder return types for a defaulted <code class="highlight"><c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>A</c-><c- o>&amp;</c-><c- p>,</c-> <c- k>const</c-> <c- n>B</c-><c- o>&amp;</c-><c- p>)</c-></code>:

  </p>
<pre class="highlight"><pre class="language-cpp highlight">
<c- k><c- k>struct</c-></c-> <c- nc><c- nc>C</c-></c-><c- p><c- p>{</c-></c->
    <c- k><c- k>auto</c-></c-><c- o><c- o>&amp;</c-></c-> <c- k><c- k>operator</c-></c-><c- o><c- o>+=</c-></c-><c- p><c- p>(</c-></c-><c- n><c- n>A</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>,</c-></c-> <c- k><c- k>const</c-></c-> <c- n><c- n>B</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>)</c-></c-> <c- o><c- o>=</c-></c-> <c- k><c- k>default</c-></c-><c- p><c- p>;</c-></c->               <c- c1><c- c1>//Well-formed, deduces to A&amp;</c-></c->
    <c- k><c- k>decltype</c-></c-><c- p><c- p>(</c-></c-><c- k><c- k>auto</c-></c-><c- p><c- p>)</c-></c-> <c- k><c- k>operator</c-></c-><c- o><c- o>+=</c-></c-><c- p><c- p>(</c-></c-><c- n><c- n>A</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>,</c-></c-> <c- k><c- k>const</c-></c-> <c- n><c- n>B</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>)</c-></c-> <c- o><c- o>=</c-></c-> <c- k><c- k>default</c-></c-><c- p><c- p>;</c-></c->      <c- c1><c- c1>//Well-formed, deduces to A&amp;</c-></c->
    <c- k><c- k>auto</c-></c-><c- o><c- o>&amp;&amp;</c-></c-> <c- k><c- k>operator</c-></c-><c- o><c- o>+=</c-></c-><c- p><c- p>(</c-></c-><c- n><c- n>A</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>,</c-></c-> <c- k><c- k>const</c-></c-> <c- n><c- n>B</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>)</c-></c-> <c- o><c- o>=</c-></c-> <c- k><c- k>default</c-></c-><c- p><c- p>;</c-></c->              <c- c1><c- c1>//Well-formed, deduces to A&amp;</c-></c->
    <c- k><c- k>auto</c-></c-><c- o><c- o>*</c-></c-> <c- k><c- k>operator</c-></c-><c- o><c- o>+=</c-></c-><c- p><c- p>(</c-></c-><c- n><c- n>A</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>,</c-></c-> <c- k><c- k>const</c-></c-> <c- n><c- n>B</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>)</c-></c-> <c- o><c- o>=</c-></c-> <c- k><c- k>default</c-></c-><c- p><c- p>;</c-></c->               <c- c1><c- c1>//Ill-formed, deduction fails</c-></c->
    <c- k><c- k>auto</c-></c-> <c- k><c- k>operator</c-></c-><c- o><c- o>+=</c-></c-><c- p><c- p>(</c-></c-><c- n><c- n>A</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>,</c-></c-> <c- k><c- k>const</c-></c-> <c- n><c- n>B</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>)</c-></c-> <c- o><c- o>=</c-></c-> <c- k><c- k>default</c-></c-><c- p><c- p>;</c-></c->                <c- c1><c- c1>//Ill-formed, A is not A&amp;</c-></c->
    <c- k><c- k>const</c-></c-> <c- k><c- k>auto</c-></c-><c- o><c- o>&amp;</c-></c-> <c- k><c- k>operator</c-></c-><c- o><c- o>+=</c-></c-><c- p><c- p>(</c-></c-><c- n><c- n>A</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>,</c-></c-> <c- k><c- k>const</c-></c-> <c- n><c- n>B</c-></c-><c- o><c- o>&amp;</c-></c-><c- p><c- p>)</c-></c-> <c- o><c- o>=</c-></c-> <c- k><c- k>default</c-></c-><c- p><c- p>;</c-></c->         <c- c1><c- c1>//Ill-formed, const A&amp; is not A&amp;</c-></c->
<c- p><c- p>};</c-></c->
</pre>
</pre>
   </div>
   <p>As P2952 is in the CWG queue for C++29, we will include wording relative to it in this paper.</p>
   <h3 class="heading settled" data-level="6.3" id="others-P2953"><span class="secno">6.3. </span><span class="content">P2953 Forbid defaulting operator=(X&amp;&amp;) &amp;&amp;</span><a class="self-link" href="#others-P2953"></a></h3>
   
<a data-link-type="biblio" href="#biblio-p2953" title="Forbid defaulting operator=(X&amp;&amp;) &amp;&amp;">[P2953]</a> seeks to explicitly ban defaulted copy- or move-assignment operators from operating on an rvalue ref-qualified objects; either by defining them as deleted or by making them ill-formed depending on WG21 feedback. As compound assignment operators are still assignment operators, and signatures such as <code class="highlight"><c- n>A</c-><c- o>&amp;</c-> <c- k>operator</c-><c- o>+=</c-><c- p>(</c-><c- n>A</c-><c- o>&amp;&amp;</c-> <c- n>lhs</c-><c- p>,</c-> <c- k>const</c-> <c- n>B</c-><c- o>&amp;</c-> <c- n>rhs</c-><c- p>)</c-> <c- o>=</c-> <c- k>default</c-><c- p>;</c-></code> seem generally implausible, we recommend that defaulted compound assignment operators fall under the same scope as defaulted copy- and move-assignment operators with respect to P2953 and should also be defined as deleted or made ill-formed as that paper progresses.


   <p>We have reached out to the author of P2953 and he agrees with this assessment. Consequently, as P2953 progresses through the WG21 process, we will revise our design and wording in parallel to it to maintain consistency.</p>
   <h3 class="heading settled" data-level="6.4" id="others-P3668"><span class="secno">6.4. </span><span class="content">P3668 Defaulting Postfix Increment and Decrement Operations</span><a class="self-link" href="#others-P3668"></a></h3>
   
<a data-link-type="biblio" href="#biblio-p3668" title="Defaulting postfix increment and decrement operations">[P3668]</a> proposes that postfix increment and decrement operators should be defaultable, in the same way that this paper proposes that compound assignment operators should be defaultable. We see no conflicts between the two papers, and note that the rules surrounding explicitly defaulted functions are consistent between the two papers, and consistent with the existing standard.


   <p>As P3668 is currently in CWG for C++29, we will provide wording relative to it.</p>
   <h2 class="heading settled" data-level="7" id="acknowledgements"><span class="secno">7. </span><span class="content">Acknowledgements</span><a class="self-link" href="#acknowledgements"></a></h2>
   <p>Many thanks to Matthias Wippich for his insight into reflection, and for providing the example in <a href="#alternatives-reflection">§ 5.4 Reflection Solutions</a>. Many thanks also go to Rodrigo Fernandes for reviewing the initial draft.</p>
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

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

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

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

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

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

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


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

    tocNav.appendChild(toggle);
  }

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

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

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

})();
</script>
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-cppdev-2025">[CppDev-2025]
   <dd><a href="https://isocpp.org/files/papers/CppDevSurvey-2025-summary.pdf"><cite>2025 Annual C++ Developer Survey 'Lite'</cite></a>. URL: <a href="https://isocpp.org/files/papers/CppDevSurvey-2025-summary.pdf">https://isocpp.org/files/papers/CppDevSurvey-2025-summary.pdf</a>
   <dt id="biblio-p1046">[P1046]
   <dd>David Stone. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1046r2.html"><cite>Automatically Generate More Operators</cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1046r2.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1046r2.html</a>
   <dt id="biblio-p1046-ewg">[P1046-EWG]
   <dd>EWG. <a href="https://wiki.edg.com/bin/view/Wg21belfast/P1046-EWG"><cite>EWG comments from the Belfast meeting</cite></a>. URL: <a href="https://wiki.edg.com/bin/view/Wg21belfast/P1046-EWG">https://wiki.edg.com/bin/view/Wg21belfast/P1046-EWG</a>
   <dt id="biblio-p2825">[P2825]
   <dd>Gašper Ažman, Bronek Kozicki. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2825r5.html"><cite>Overload resolution hook: declcall( unevaluated-call-expression )</cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2825r5.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2825r5.html</a>
   <dt id="biblio-p2952">[P2952]
   <dd>Arthur O'Dwyer, Matthew Taylor. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2952r2.html"><cite>auto&amp; operator=(X&amp;&amp;) = default</cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2952r2.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2952r2.html</a>
   <dt id="biblio-p2953">[P2953]
   <dd>Arthur O'Dwyer. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2953r1.html"><cite>Forbid defaulting operator=(X&amp;&amp;) &amp;&amp;</cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2953r1.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2953r1.html</a>
   <dt id="biblio-p3039">[P3039]
   <dd>David Stone. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3039r0.html"><cite>Automatically Generate operator-></cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3039r0.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p3039r0.html</a>
   <dt id="biblio-p3294">[P3294]
   <dd>Andrei Alexandrescu; Barry Revzin; Daveed Vandevoorde. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3294r2.html"><cite>Code Injection with Token Sequences</cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3294r2.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3294r2.html</a>
   <dt id="biblio-p3668">[P3668]
   <dd>Matthew Taylor, Alex. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3668r2.html"><cite>Defaulting postfix increment and decrement operations</cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3668r2.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3668r2.html</a>
  </dl>