<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2023-10-11" />
  <title>Stop Forcing `std::move` to Pessimize</title>
  <style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.csl-block{margin-left: 1.5em;}
ul.task-list{list-style: none;}
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ background-color: #f6f8fa; }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span { } 
code span.al { color: #ff0000; } 
code span.an { } 
code span.at { } 
code span.bn { color: #9f6807; } 
code span.bu { color: #9f6807; } 
code span.cf { color: #00607c; } 
code span.ch { color: #9f6807; } 
code span.cn { } 
code span.co { color: #008000; font-style: italic; } 
code span.cv { color: #008000; font-style: italic; } 
code span.do { color: #008000; } 
code span.dt { color: #00607c; } 
code span.dv { color: #9f6807; } 
code span.er { color: #ff0000; font-weight: bold; } 
code span.ex { } 
code span.fl { color: #9f6807; } 
code span.fu { } 
code span.im { } 
code span.in { color: #008000; } 
code span.kw { color: #00607c; } 
code span.op { color: #af1915; } 
code span.ot { } 
code span.pp { color: #6f4e37; } 
code span.re { } 
code span.sc { color: #9f6807; } 
code span.ss { color: #9f6807; } 
code span.st { color: #9f6807; } 
code span.va { } 
code span.vs { color: #9f6807; } 
code span.wa { color: #008000; font-weight: bold; } 
code.diff {color: #898887}
code.diff span.va {color: #006e28}
code.diff span.st {color: #bf0303}
</style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}

ul {
list-style-type: none;
padding-left: 2.5em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
ol {
padding-left: 2.5em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}

#TOC ul > li:before {
content: none;
}
#TOC > ul {
padding-left: 0;
}

.toc-section-number {
margin-right: 0.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Stop Forcing
<code class="sourceCode default">std::move</code> to Pessimize</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2991R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2023-10-11</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      SG20 (Education)<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Brian Bi<br>&lt;<a href="mailto:bbi10@bloomberg.net" class="email">bbi10@bloomberg.net</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#abstract" id="toc-abstract"><span class="toc-section-number">1</span> Abstract</a></li>
<li><a href="#the-problem" id="toc-the-problem"><span class="toc-section-number">2</span> The problem</a></li>
<li><a href="#the-solution" id="toc-the-solution"><span class="toc-section-number">3</span> The solution</a></li>
<li><a href="#should-the-core-language-have-special-cases-for-library-entities" id="toc-should-the-core-language-have-special-cases-for-library-entities"><span class="toc-section-number">4</span> Should the core language have
special cases for library entities?</a></li>
<li><a href="#how-many-programs-will-be-broken-by-this-change" id="toc-how-many-programs-will-be-broken-by-this-change"><span class="toc-section-number">5</span> How many programs will be broken by
this change?</a></li>
<li><a href="#alternative-solutions" id="toc-alternative-solutions"><span class="toc-section-number">6</span>
Alternative solutions</a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">7</span> Wording</a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">8</span> References</a></li>
</ul>
</div>
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>Those who learn C++ are taught to use
<code class="sourceCode default">std::move</code> when initializing a
new object that needs to hold the value of a given source lvalue and the
source object no longer needs to hold that value. However, an exception
to this guideline is soon introduced: when returning the name of a local
variable, applying <code class="sourceCode default">std::move</code> can
inhibit the named-return-value optimization (NRVO). This paper proposes
to eliminate this exception by making the expression
<code class="sourceCode default">std::move(x)</code> <em>NRVO
eligible</em> when <code class="sourceCode default">x</code> is NRVO
eligible. Doing so will improve the teachability of move semantics in
C++.</p>
<h1 data-number="2" id="the-problem"><span class="header-section-number">2</span> The problem<a href="#the-problem" class="self-link"></a></h1>
<p>The following code illustrates a familiar pattern in which named
objects must be created, modified, and then moved from.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> readStrings<span class="op">(</span><span class="dt">int</span> numStrings<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>vector<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span> result;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>string string;</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="cf">while</span> <span class="op">(</span>numStrings<span class="op">--)</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>cin <span class="op">&gt;&gt;</span> string;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>        result<span class="op">.</span>push_back<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>string<span class="op">))</span>;</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> result;</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>In the above code, moving from both
<code class="sourceCode default">string</code> and
<code class="sourceCode default">result</code> is appropriate, as
neither object needs to hold its value any longer after those values
have respectively been transferred to an element of
<code class="sourceCode default">result</code> and to the returned
object. Both <code class="sourceCode default">string</code> and
<code class="sourceCode default">result</code> are named objects.
However, in only one case should
<code class="sourceCode default">std::move</code> be applied to convert
its operand from an lvalue to an xvalue and force a move to occur.</p>
<p>In all versions of C++,
<code class="sourceCode default">return result;</code> permits (but does
not require) the compiler to make the local variable
<code class="sourceCode default">result</code> an alias for the returned
object, obviating the need for any move at all. This optimization is
known as <em>named-return-value optimization</em> (NRVO). In all
versions since C++11, if the compiler declines to perform NRVO, then the
<em>id-expression</em> <code class="sourceCode default">result</code>
will be treated as an xvalue in the
<code class="sourceCode default">return</code> statement, even though it
is an lvalue when appearing elsewhere.</p>
<p>Writing
<code class="sourceCode default">return std::move(result);</code> is not
only unnecessary, but also detrimental to performance: NRVO does not
occur when the operand of the
<code class="sourceCode default">return</code> statement is anything
other than the name of a local variable. Therefore, adding a call to
<code class="sourceCode default">std::move</code> can force the compiler
to actually create a separate
<code class="sourceCode default">result</code> object on the stack frame
of <code class="sourceCode default">readStrings</code> and then perform
the move from that object to the returned object (often allocated on the
stack frame of the caller).</p>
<p>Those learning C++ are taught to write
<code class="sourceCode default">std::move(string)</code> because
<code class="sourceCode default">string</code> is an lvalue referring to
an object that no longer needs to hold its value after that value has
been passed to the function
<code class="sourceCode default">push_back</code>. I’ll call this the
<em>When to Move Rule</em>.</p>
<p><span style="display: inline-block; background-color: #c0ffc0; padding: 0.5em; margin: 0.5em; border: 1px solid #0c0">
<code class="sourceCode default">std::move</code> should be applied to
an lvalue if the object to which the lvalue refers no longer needs to
hold its value after the current operation. </span></p>
<p>While the When to Move Rule indicates some uses of
<code class="sourceCode default">std::move</code> that are unnecessary
(such as when the operand is of a trivially copyable type), in only a
single case is following the When to Move Rule likely to be a
pessimization, and I will refer to this case as the <em>When Not to Move
Rule</em>:</p>
<p><span style="display: inline-block; background-color: #ffc0c0; padding: 0.5em; margin: 0.5em; border: 1px solid #c00">
Notwithstanding the When to Move Rule,
<code class="sourceCode default">std::move</code> should not be used
when the operand of a <code class="sourceCode default">return</code>
statement is the name of a local variable whose type is the same as the
return type of the function (modulo top-level cv-qualification) since
the use of <code class="sourceCode default">std::move</code> can inhibit
NRVO. </span></p>
<p>The When Not to Move Rule is hard to learn and remember. Novices
should not have to think about compiler optimizations that may or may
not happen, and the scope of the exception seems arbitrary unless the
developer understands the boundaries of NRVO. Because even experienced
C++ programmers sometimes wonder why NRVO requires an exact match in
types, one cannot expect a novice to remember the exact circumstances
under which NRVO might happen (which contraindicates the use of
<code class="sourceCode default">std::move</code>).</p>
<p>Thanks to the adoption of <span class="citation" data-cites="P1155R3">[<a href="#ref-P1155R3" role="doc-biblioref">P1155R3</a>]</span> into C++20 as a defect report
(DR), the When Not to Move Rule can be simplified:
“<code class="sourceCode default">std::move</code> should not be used
when the operand of a <code class="sourceCode default">return</code>
statement is the name of a local variable, full stop.” This version of
the rule is simpler than the version above. Even still, the fact that
the When Not to Move Rule needs to be explained at all is a teachability
burden. Novices should neither have to attempt to understand NRVO, nor
should they have to think about lvalues automatically becoming rvalues
in certain positions, especially considering that understanding which
expressions are even lvalues is hard enough. Yet, these concepts are
both required to explain why violating the When Not to Move Rule can
make the performance of code only worse, never better.</p>
<p>In C++23, the When Not to Move Rule is actually part of the When to
Move Rule, because <span class="citation" data-cites="P2266R3">[<a href="#ref-P2266R3" role="doc-biblioref">P2266R3</a>]</span>
reclassified the name of a local variable as an xvalue when that name is
the operand of a <code class="sourceCode default">return</code>
statement. For the reasons explained in the previous paragraph, it is
unclear whether shifting the complexity of the When Not to Move Rule
into the definitions of the value categories makes the actual
recommended practice any easier to understand.</p>
<h1 data-number="3" id="the-solution"><span class="header-section-number">3</span> The solution<a href="#the-solution" class="self-link"></a></h1>
<p>The conditions under which NRVO can occur for a
<code class="sourceCode default">return</code> statement are specified
in § [class.copy.elision]p1.1<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>: The operand must be an
<em>id-expression</em> naming a nonvolatile object with automatic
storage duration that is not a function parameter nor the parameter of a
<code class="sourceCode default">catch</code> clause and whose type,
ignoring cv-qualification, is the same as the return type of the
function. Call these expressions <em>NRVO eligible</em>. I propose that
when the expression <code class="sourceCode default">E</code> is NRVO
eligible, the following expressions should also be NRVO eligible:</p>
<ul>
<li><code class="sourceCode default">std::move(E)</code> or, more
generally, <code class="sourceCode default">F(E)</code> when
<code class="sourceCode default">F</code> is an <em>id-expression</em>
that denotes <code class="sourceCode default">std::move</code> after
name lookup</li>
<li><code class="sourceCode default">static_cast&lt;T&gt;(E)</code>,
where <code class="sourceCode default">T</code> is any <em>type-id</em>
denoting an rvalue reference to the return type</li>
<li><code class="sourceCode default">(T)E</code>, where
<code class="sourceCode default">T</code> is any <em>type-id</em>
denoting an rvalue reference to the return type</li>
<li><code class="sourceCode default">T(E)</code>, where
<code class="sourceCode default">T</code> is any
<em>simple-type-specifier</em> denoting an rvalue reference to the
return type</li>
</ul>
<p>Redundant parentheses are allowed around both <em>E</em> and the cast
expression, under § [expr.prim.paren].</p>
<p>The first of the above forms is the one beginners will use most
often, but the remaining forms should also be allowed for
consistency.</p>
<p>I further propose that the above change should be considered a DR so
that compilers will implement it in earlier language versions.</p>
<p>After this change is made to the Standard, the When Not to Move Rule
will no longer need to be taught.</p>
<p>Note, however, that adopting this proposal will neither force
implementations to perform NRVO in any situation where they currently do
not, nor will any implementations be forced to generate code for
<code class="sourceCode default">return std::move(x);</code> that is
equally optimized as the code generated for
<code class="sourceCode default">return x;</code>. This proposal would
only <em>allow</em> implementations to do so.</p>
<h1 data-number="4" id="should-the-core-language-have-special-cases-for-library-entities"><span class="header-section-number">4</span> Should the core language have
special cases for library entities?<a href="#should-the-core-language-have-special-cases-for-library-entities" class="self-link"></a></h1>
<p>The change proposed in this paper would give special core-language
treatment for the Standard Library entity
<code class="sourceCode default">std::move</code>. This change is
unlikely to present any implementation challenges, since Clang and GCC
have already started treating expressions of the form
<code class="sourceCode default">std::move(E)</code> as if the
corresponding cast had been written explicitly (thus avoiding the
overhead of instantiating the function template
<code class="sourceCode default">std::move</code>). Still, one might
object that such special treatment is unusual when it occurs in the core
language specification.</p>
<p>However, such special cases already exist within the core language.
This is illustrated by the following nonexhaustive list of such special
cases:</p>
<ul>
<li><code class="sourceCode default">std::byte</code> is exempt from
strict aliasing: A glvalue of type
<code class="sourceCode default">std::byte</code> can be used to access
the value of an object of any type. No other enumeration type has this
permission.</li>
<li><code class="sourceCode default">std::initializer_list</code> has
special rules for deduction: When a function template has a parameter of
type
<code class="sourceCode default">std::initializer_list&lt;T&gt;</code>,
with <code class="sourceCode default">T</code> being a type template
argument, <code class="sourceCode default">T</code> can be deduced when
the corresponding argument is a <em>braced-init-list</em>. No other
class template supports such deduction.</li>
<li>Member functions of
<code class="sourceCode default">std::allocator&lt;T&gt;</code> have
special permission to be called during constant evaluation despite being
defined in terms of expressions that are not permitted in constant
evaluation.</li>
<li>Structured bindings use
<code class="sourceCode default">std::tuple_size</code> and
<code class="sourceCode default">std::tuple_element</code>.</li>
</ul>
<p>The existence of these special cases reflects the design principle
that the core language is not truly separate from the Standard Library;
they are simply described in different sections of the Standard.</p>
<h1 data-number="5" id="how-many-programs-will-be-broken-by-this-change"><span class="header-section-number">5</span> How many programs will be broken
by this change?<a href="#how-many-programs-will-be-broken-by-this-change" class="self-link"></a></h1>
<p>The change proposed by this paper can alter the behavior of existing
code, because whether NRVO is applied affects the observable behavior of
a program. Such a change can be considered <em>breaking</em> for a
program whose correct functioning depends on NRVO <em>not</em>
occurring, e.g., a test driver that counts the number of times a move
constructor is called. A programmer who is aware of NRVO would consider
writing such code inadvisable, but others might do so anyway, unaware of
the impact.</p>
<p>I expect that the actual amount of breakage caused by improvements to
NRVO is relatively small; were it not so, then discretionary
improvements to NRVO under the current rules (i.e., a newer version of a
compiler choosing to implement NRVO in a situation where an older
version did not) would also frequently cause similar problems. However,
this issue is rarely mentioned among the issues that need to be fixed in
a codebase during a toolchain upgrade.</p>
<p>Some users might be deliberately using
<code class="sourceCode default">std::move</code> to suppress NRVO under
circumstances where NRVO occurring is undesirable. For those users, the
change proposed by this paper would be breaking, even if other changes
to NRVO might not be breaking. This pattern probably occurs
infrequently, because deliberately suppressing NRVO is rarely
desirable.</p>
<p>If this proposal receives positive feedback in the EWG, the amount of
breakage could be gauged more precisely by running test suites for large
open source projects after implementing the proposed change in a
compiler, should EWG consider such implementation experience
necessary.</p>
<h1 data-number="6" id="alternative-solutions"><span class="header-section-number">6</span> Alternative solutions<a href="#alternative-solutions" class="self-link"></a></h1>
<p>As an alternative, an expression could be considered NRVO-eligible
when it is an xvalue that refers to a local variable whose type is the
same as the function return type (modulo top-level cv-qualification).
This rule would make NRVO eligibility a runtime property in theory; in
practice, implementations would be able to perform NRVO only when they
can prove that the operand of the
<code class="sourceCode default">return</code> statement always refers
to one particular local variable.</p>
<p>Compared with the proposed solution, this alternative solution has
the elegance of avoiding any special case for
<code class="sourceCode default">std::move</code>. However, by allowing
NRVO in cases that lack clarity regarding whether the compiler will be
able to prove that NRVO is allowed, this alternative rule can be a
source of nonportable behavior. The practical downside seems to outweigh
the theoretical elegance of not making
<code class="sourceCode default">std::move</code> a special case. An
additional downside is that, under this alternative solution, how to
write a <code class="sourceCode default">return</code> statement that
forces NRVO <em>not</em> to occur, which might be desirable in some
circumstances, is unclear.</p>
<p>Another alternative solution that would reduce implementation
divergence, while also avoiding special-casing of
<code class="sourceCode default">std::move</code>, is to require a trial
constant evaluation when the operand of a
<code class="sourceCode default">return</code> statement is an xvalue
with the same type as the function return type (modulo top-level
cv-qualification); if this trial constant evaluation succeeds and the
result refers to a local variable, then NRVO would be permitted to
occur. If the result of evaluating the operand depends on the value of
any function parameters or other information that is known only at run
time, then the trial constant evaluation will fail.</p>
<p>Such a trial constant evaluation would perhaps be detrimental to
compile times, might pose implementation challenges, might be difficult
to specify and give rise to CWG issues, and might fail to achieve the
objective of avoiding implementation divergence due to its complexity.
(For example, what should the implementation do if the result of the
trial constant evaluation differs from what would actually occur at run
time, e.g., because of the use of
<code class="sourceCode default">if consteval</code>?) Finally,
backporting such a trial constant evaluation to earlier language
versions is likely to be unfeasible (i.e., adopting this alternative as
a DR), which means that pessimization would continue to be required in
older language modes.</p>
<h1 data-number="7" id="wording"><span class="header-section-number">7</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>The proposed wording is relative to <span class="citation" data-cites="N4958">[<a href="#ref-N4958" role="doc-biblioref">N4958</a>]</span>.</p>
<p>Edit § [class.copy.elision]p1.1 as shown.</p>
<blockquote>
<p>in a <code class="sourceCode default">return</code> statement in a
function with a class return type, when the <em>expression</em> is <span class="add" style="color: #006e28"><ins>NRVO eligible (see below) and
refers to</ins></span><span class="rm" style="color: #bf0303"><del>the
name of</del></span> a non-volatile object with automatic storage
duration (other than a function parameter or a variable introduced by
the <em>exception-declaration</em> of a <em>handler</em>
([except.handle])) with the same type (ignoring cv-qualification) as the
function return type, the copy/move operation can be omitted by
constructing the object directly into the function call’s return
object</p>
</blockquote>
<p>Edit § [class.copy.elision]p1.2 as shown.</p>
<blockquote>
<p>in a <em>throw-expression</em> ([expr.throw]), when the operand is
<span class="add" style="color: #006e28"><ins>NRVO eligible (see below)
and refers to</ins></span><span class="rm" style="color: #bf0303"><del>the name of</del></span> a non-volatile
object with automatic storage duration (other than a function or
catch-clause parameter) that belongs to a scope that does not contain
the innermost enclosing <em>compound-statement</em> associated with a
<em>try-block</em> (if there is one), the copy/move operation can be
omitted by constructing the object directly into the exception
object</p>
</blockquote>
<p>Add a new paragraph after § [class.copy.elision]p1:</p>
<blockquote>
<div class="add" style="color: #006e28">
<p>An expression is <em>NRVO eligible</em> if it is:</p>
<ul>
<li>an <em>id-expression</em>,</li>
<li><code class="sourceCode default">(</code> <em>E</em>
<code class="sourceCode default">)</code>, where <em>E</em> is NRVO
eligible, or</li>
<li>one of the below expressions, where <em>E</em> is NRVO eligible and
<code class="sourceCode default">T</code> is the rvalue reference type
whose referenced type is that of <em>E</em>:
<ul>
<li><em>F</em><code class="sourceCode default">(</code><em>E</em><code class="sourceCode default">)</code>,
where <em>F</em> is a (possibly parenthesized) <em>id-expression</em>
denoting <code class="sourceCode default">::std::move</code>
([forward])</li>
<li><code class="sourceCode default">static_cast&lt;</code><em>type-id</em><code class="sourceCode default">&gt;(</code><em>E</em><code class="sourceCode default">)</code>
or
<code class="sourceCode default">(</code><em>type-id</em><code class="sourceCode default">)</code><em>E</em>,
where the <em>type-id</em> denotes
<code class="sourceCode default">T</code></li>
<li><em>simple-type-specifier</em><code class="sourceCode default">(</code><em>E</em><code class="sourceCode default">)</code>,
where the <em>simple-type-specifier</em> denotes
<code class="sourceCode default">T</code></li>
</ul></li>
</ul>

</div>
</blockquote>
<h1 data-number="8" id="bibliography"><span class="header-section-number">8</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" role="doc-bibliography">
<div id="ref-N4958" class="csl-entry" role="doc-biblioentry">
[N4958] Thomas Köppe. 2023-08-14. Working Draft, Programming Languages —
C++. <a href="https://wg21.link/n4958"><div class="csl-block">https://wg21.link/n4958</div></a>
</div>
<div id="ref-P1155R3" class="csl-entry" role="doc-biblioentry">
[P1155R3] Arthur O’Dwyer, David Stone. 2019-06-17. More implicit moves.
<a href="https://wg21.link/p1155r3"><div class="csl-block">https://wg21.link/p1155r3</div></a>
</div>
<div id="ref-P2266R3" class="csl-entry" role="doc-biblioentry">
[P2266R3] Arthur O’Dwyer. 2022-03-26. Simpler implicit move. <a href="https://wg21.link/p2266r3"><div class="csl-block">https://wg21.link/p2266r3</div></a>
</div>
</div>
<section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>All citations to the Standard are to working draft <span class="citation" data-cites="N4958">[<a href="#ref-N4958" role="doc-biblioref">N4958</a>]</span> unless otherwise specified.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
