<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang=""><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <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-11-07">
  <title>Make std::ignore a first-class object</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.csl-block{margin-left: 1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

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

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

code.sourceCode > span { display: inline; }
</style>
  <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">Make std::ignore a
first-class object</h1>
<table style="border:none;float:right">
  <tbody><tr>
    <td>Document #:</td>
    <td>P2968R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2023-11-07</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>
      WG21 - Library &amp; Library Evolution<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Peter Sommerlad<br>&lt;<a href="mailto:peter.cpp@sommerlad.ch" class="email">peter.cpp@sommerlad.ch</a>&gt;<br>
    </td>
  </tr>
</tbody></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<span></span></a></li>
<li><a href="#history" id="toc-history"><span class="toc-section-number">2</span> History<span></span></a>
<ul>
<li><a href="#r1-incorporating-some-discussion" id="toc-r1-incorporating-some-discussion"><span class="toc-section-number">2.1</span> R1 incorporating some
discussion<span></span></a></li>
<li><a href="#r0-initial-revision" id="toc-r0-initial-revision"><span class="toc-section-number">2.2</span> R0 initial
revision<span></span></a></li>
</ul></li>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">3</span> Introduction<span></span></a>
<ul>
<li><a href="#non-tuple-applications-of-stdignore" id="toc-non-tuple-applications-of-stdignore"><span class="toc-section-number">3.1</span> Non-tuple applications of
<code class="sourceCode default">std::ignore</code><span></span></a></li>
<li><a href="#lwg-issue-2933" id="toc-lwg-issue-2933"><span class="toc-section-number">3.2</span> <span>LWG issue
2933</span><span></span></a></li>
<li><a href="#lwg-issue-3978" id="toc-lwg-issue-3978"><span class="toc-section-number">3.3</span> <span>LWG issue
3978</span><span></span></a></li>
</ul></li>
<li><a href="#mailing-list-discussions" id="toc-mailing-list-discussions"><span class="toc-section-number">4</span> Mailing List
discussions<span></span></a></li>
<li><a href="#questions-to-lewg" id="toc-questions-to-lewg"><span class="toc-section-number">5</span> Questions to
LEWG<span></span></a></li>
<li><a href="#questions-to-lwg" id="toc-questions-to-lwg"><span class="toc-section-number">6</span> Questions to
LWG<span></span></a></li>
<li><a href="#impact-on-existing-code" id="toc-impact-on-existing-code"><span class="toc-section-number">7</span> Impact on existing
code<span></span></a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">8</span> Wording<span></span></a></li>
<li><a href="#references" id="toc-references"><span class="toc-section-number">9</span> References<span></span></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>All major open source C++ library implementations provide a suitably
implemented <code class="sourceCode default">std::ignore</code> allowing
a no-op assignment from any object type. However, according to some C++
experts the standard doesn’t bless its use beyond
<code class="sourceCode default">std::tie</code>. This paper also
resolves issue lwg2933 by proposing to make the use of
<code class="sourceCode cpp">std<span class="op">::</span>ignore</code>
as the left-hand operand of an assignment expression official.</p>
<h1 data-number="2" id="history"><span class="header-section-number">2</span> History<a href="#history" class="self-link"></a></h1>
<h2 data-number="2.1" id="r1-incorporating-some-discussion"><span class="header-section-number">2.1</span> R1 incorporating some
discussion<a href="#r1-incorporating-some-discussion" class="self-link"></a></h2>
<ul>
<li>mention bit-fields and suggest that they cannot be a valid RHS to
<code class="sourceCode default">std::ignore</code>’s assignment,
addresses <a href="https://wg21.link/lwg3978">LWG 3978</a>. Add question
if RHS non-volatile bit-fields should be supported at all.</li>
<li>Incorporate (most of) Arthur O’Dwyer’s input and suggestions,
including his analysis of existing major implementations.</li>
<li>recommend spec as code using
<code class="sourceCode default">operator=(auto&amp;&amp;)</code>
preventing bit-fields as rhs, to prevent accidental side-effects through
volatile bit-fields.</li>
</ul>
<h2 data-number="2.2" id="r0-initial-revision"><span class="header-section-number">2.2</span> R0 initial revision<a href="#r0-initial-revision" class="self-link"></a></h2>
<ul>
<li>Adresses <a href="https://wg21.link/lwg2933">LWG 2933</a></li>
<li>Takes up some mailing list discussion.</li>
</ul>
<h1 data-number="3" id="introduction"><span class="header-section-number">3</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>All major C++ open source standard libraries provide similar
implementations for the type of
<code class="sourceCode default">std::ignore</code>. However, the
semantics of <code class="sourceCode default">std::ignore</code>, while
useful beyond, are only specified in the context of
<code class="sourceCode default">std::tie</code>.</p>
<h2 data-number="3.1" id="non-tuple-applications-of-stdignore"><span class="header-section-number">3.1</span> Non-tuple applications of
<code class="sourceCode default">std::ignore</code><a href="#non-tuple-applications-of-stdignore" class="self-link"></a></h2>
<p>Programming guidelines for C++ safety-critical systems consider all
named functions with a non-void return type similar to having the
attribute <code class="sourceCode default">[[nodiscard]]</code>.</p>
<p>As of today, the means to disable diagnostic is a static cast to void
spelled with a C-style cast
<code class="sourceCode default">(void) foo();</code>. This provides a
teachability issue, because, while C-style casts are banned, such a
C-style cast need to be taught. None of the guidelines I am aware of,
dared to ask for a <code class="sourceCode default">static_cast&lt;void&gt;( foo() );</code> in
those situation.</p>
<p>With the semantics provided by the major standard library
implementations and the semantics of the example implementation given in
the cppreference.com site, it would be much more documenting intent to
write</p>
<p><code class="sourceCode default">std::ignore = foo();</code></p>
<p>instead of the C-style void-cast.</p>
<p>To summarize the proposed change:</p>
<ol type="1">
<li>better self-documenting code telling the intent</li>
<li>Improved teachability of C++ to would-be C++ programmers in
safety-critical environments</li>
</ol>
<h2 data-number="3.2" id="lwg-issue-2933"><span class="header-section-number">3.2</span> <a href="https://wg21.link/lwg2933">LWG issue 2933</a><a href="#lwg-issue-2933" class="self-link"></a></h2>
<p>This issue asks for a better specification of the type of
<code class="sourceCode cpp">std<span class="op">::</span>ignore</code>
by saying that all constructors and assignment operators are constexpr.
I don’t know if that needs to be said that explicitly, but the
assignment operator template that is used by all implementations should
be mentioned as being constexpr and applicable to the global constant
<code class="sourceCode cpp">std<span class="op">::</span>ignore</code>.</p>
<h2 data-number="3.3" id="lwg-issue-3978"><span class="header-section-number">3.3</span> <a href="https://wg21.link/lwg3978">LWG issue 3978</a><a href="#lwg-issue-3978" class="self-link"></a></h2>
<p>This issue claims that the “no further effect” is not implementable
when the rhs is a volatile bit-field. Providing a code-wise
specification, we can eliminate the situation, because the rhs will not
allow bit-fields <code class="sourceCode cpp"><span class="op">(</span><span class="kw">auto</span><span class="op">&amp;&amp;)</span></code>
or will allow only non-volatile bit-fields <code class="sourceCode cpp"><span class="op">(</span><span class="kw">auto</span> <span class="kw">const</span><span class="op">&amp;)</span></code>.</p>
<h1 data-number="4" id="mailing-list-discussions"><span class="header-section-number">4</span> Mailing List discussions<a href="#mailing-list-discussions" class="self-link"></a></h1>
<p>After some initial drafts posted to lib-ext@lists.isocpp.org I got
some further feedback on motivation and desire to move ignore to a
separate header or utility:</p>
<p>Additional motivating usage by Arthur O’Dwyer:</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>  <span class="kw">struct</span> DevNullIterator <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> difference_type <span class="op">=</span> <span class="dt">int</span>;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span><span class="op">&amp;</span> <span class="kw">operator</span><span class="op">++()</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span>; <span class="op">}</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span><span class="op">&amp;</span> <span class="kw">operator</span><span class="op">++(</span><span class="dt">int</span><span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span>; <span class="op">}</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="kw">operator</span><span class="op">*()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> std<span class="op">::</span>ignore; <span class="op">}</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> a<span class="op">[</span><span class="dv">100</span><span class="op">]</span>;</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>ranges<span class="op">::</span>copy<span class="op">(</span>a, a<span class="op">+</span><span class="dv">100</span>, DevNullIterator<span class="op">())</span>;</span></code></pre></div>
<p>Giuseppe D’Angelo: As an extra, could it be possible to move
<code class="sourceCode default">std::ignore</code> out of
<code class="sourceCode default">&lt;tuple&gt;</code> and into
<code class="sourceCode default">&lt;utility&gt;</code> or possibly its
own header <code class="sourceCode default">&lt;ignore&gt;</code>?</p>
<p>Ville Voutilainen suggested a specification as code, such as:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co">// 22.4.5, tuple creation functions</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>ignore_type</em> <span class="op">{</span> <span class="co">// <em>exposition only</em></span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">auto</span><span class="op">&amp;&amp;)</span> <span class="kw">const</span> <span class="op">&amp;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span>; <span class="op">}</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> <em>ignore_type</em> ignore;</span></code></pre></div>
<p>or even more brief by me (the lvalue ref qualification is optional,
but I put it here):</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> </span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span>  <span class="op">{</span> <span class="co">// exposition only</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">auto</span><span class="op">&amp;&amp;)</span> <span class="kw">const</span> <span class="op">&amp;</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span>; <span class="op">}</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> ignore;</span></code></pre></div>
<p>Thanks to Arthur O’Dwyer for repeating my analysis of the three major
open source library implementations.</p>
<p>Note that using
<code class="sourceCode default">auto&amp;&amp;</code> instead of
<code class="sourceCode default">auto const &amp;</code> prevents the
use of a bit-field on the right-hand side of the assignment. Here exists
implementation divergence between the different libraries.</p>
<h1 data-number="5" id="questions-to-lewg"><span class="header-section-number">5</span> Questions to LEWG<a href="#questions-to-lewg" class="self-link"></a></h1>
<p>Since there was the request to make
<code class="sourceCode cpp">std<span class="op">::</span>ignore</code>
available without having to include <code class="sourceCode cpp"><span class="op">&lt;</span>tuple<span class="op">&gt;</span></code>
the following questions are for LEWG. Note, any yes will require a
change/addition to the provided wording and would also put some burden
on implementors. An advantage might be slightly reduced compile times
for users of
<code class="sourceCode cpp">std<span class="op">::</span>ignore</code>
who do not need anything else from header <code class="sourceCode cpp"><span class="op">&lt;</span>tuple<span class="op">&gt;</span></code>.</p>
<ul>
<li>Should
<code class="sourceCode cpp">std<span class="op">::</span>ignore</code>
be made available via its own header
<code class="sourceCode default">&lt;ignore&gt;</code> in addition to be
available via <code class="sourceCode default">&lt;tuple&gt;</code>? Y/N
(I would not suggest a new header.)</li>
<li>If no: Should
<code class="sourceCode cpp">std<span class="op">::</span>ignore</code>
be made available via header
<code class="sourceCode default">&lt;utility&gt;</code> in addition to
being available via
<code class="sourceCode default">&lt;tuple&gt;</code>? Y/N (This makes
sense in my opinion,<code class="sourceCode default">tuple_size</code>
is there as well, for example)</li>
<li>Should <code class="sourceCode cpp">std<span class="op">::</span>ignore<span class="op">::</span><span class="kw">operator</span><span class="op">=</span></code>
support non-volatile bit-fields on the right hand side
(<code class="sourceCode default">operator=(auto const&amp;)</code>) or
not (<code class="sourceCode default">operator=(auto&amp;&amp;)</code>)
?</li>
</ul>
<p>The latter question is not an issue with existing code, because
tuple’s tie() would never support bit-fields and there is actual
implementation divergence between major vendors. I don’t have a strong
opinion, but suppressing also non-volatile bit-fields helps in situation
where a bit-field containing class mixes volatile and non-volatile
members.</p>
<p>We have implementation divergence here (see below), which means we
have implementation experience both ways:</p>
<ul>
<li>libstdc++ and Microsoft both currently use
<code class="sourceCode default">(const auto&amp;)</code> (which
supports non-volatile bit-fields (which are converted to rvalue
implicitly) but not volatile bit-fields).</li>
<li>libc++ currently uses
<code class="sourceCode default">(auto&amp;&amp;)</code> (which does not
support bit-fields of any qualification). libc++ has never received a
bug report about its more-restrictive
<code class="sourceCode default">std::ignore</code>, which is currently
proposed.</li>
</ul>
<h1 data-number="6" id="questions-to-lwg"><span class="header-section-number">6</span> Questions to LWG<a href="#questions-to-lwg" class="self-link"></a></h1>
<ul>
<li>Should the specification of the type of
<code class="sourceCode cpp">std<span class="op">::</span>ignore</code>
use code or stick to a more generic text (see below)?
<ul>
<li>Note: just using text, can create an issue with using volatile
(bitfields) as RHS, where the actual read on the volatile will happen.
using <code class="sourceCode default">auto&amp;&amp;</code> as
assignment operator’s argument will prevent using a volatile bitfield on
the RHS (according to <a href="https://godbolt.org/z/88PTG1GEs">my
experiments</a> ).</li>
</ul></li>
<li>Do we need to mention “constepxr constructors” as asked for by
LWG2933? (see parenthesized text in the Wording section) I don’t think
so.</li>
<li>How would we mention avaialability from header
<code class="sourceCode default">&lt;utility&gt;</code> ? (I prepared
accordingly, thanks to Arthur’s help)</li>
</ul>
<h1 data-number="7" id="impact-on-existing-code"><span class="header-section-number">7</span> Impact on existing code<a href="#impact-on-existing-code" class="self-link"></a></h1>
<p>All three major standard library vendors (libstdc++, Microsoft,
libc++) implement <code class="sourceCode default">std::ignore</code> in
roughly the same way, but there are some minor differences that could be
ironed out by this proposal.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co">// libstdc++</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> __ignore_t <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">const</span> __ignore_t<span class="op">&amp;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;)</span> <span class="kw">const</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>      <span class="op">{</span> <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span>; <span class="op">}</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> __ignore_t ignore<span class="op">{}</span>;</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="co">// Microsoft STL</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> __ignore_t <span class="op">{</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">const</span> __ignore_t<span class="op">&amp;</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&amp;)</span> <span class="kw">const</span> <span class="kw">noexcept</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>      <span class="op">{</span> <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span>; <span class="op">}</span></span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> __ignore_t ignore<span class="op">{}</span>;</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="co">// libc++</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> __ignore_t <span class="op">{</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">const</span> __ignore_t<span class="op">&amp;</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">operator</span><span class="op">=(</span><span class="kw">auto</span><span class="op">&amp;&amp;)</span> <span class="kw">const</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>      <span class="op">{</span> <span class="cf">return</span> <span class="op">*</span><span class="kw">this</span>; <span class="op">}</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> __ignore_t<span class="op">&lt;</span><span class="dt">unsigned</span> <span class="dt">char</span><span class="op">&gt;</span> ignore <span class="op">=</span> __ignore_t<span class="op">&lt;</span><span class="dt">unsigned</span> <span class="dt">char</span><span class="op">&gt;()</span>;</span></code></pre></div>
<p>The difference between
<code class="sourceCode default">operator=(const auto&amp;)</code> and
<code class="sourceCode default">operator=(auto&amp;&amp;)</code> is
that the former will bind to non-volatile bit-field glvalues, whereas
the latter will not. If we want to support non-volatile bit-fields, we
should change the signature of
<code class="sourceCode default">ignore::operator=</code> to take
<code class="sourceCode default">(const auto&amp;)</code> instead of
<code class="sourceCode default">(auto&amp;&amp;)</code>. Neither
signature binds to <em>volatile</em> bit-field glvalues; that is <a href="https://cplusplus.github.io/LWG/issue3978">LWG3978</a>. Our
wording makes
<code class="sourceCode default">std::ignore = volatilebit.field;</code>
obviously ill-formed, which resolves LWG3978.</p>
<p>The difference between
<code class="sourceCode default">noexcept</code> and not is negligible;
we could mandate that
<code class="sourceCode default">std::ignore::operator=</code> be
noexcept, or we could leave it non-noexcept. The vendor is already
permitted to strengthen the noexceptness of any standard library
function; Microsoft takes advantage of this freedom already. We suggest
that as long as we’re touching this area anyway, we should go ahead and
add the <code class="sourceCode default">noexcept</code>.</p>
<p>The programmer can detect whether
<code class="sourceCode default">ignore</code>’s type is a template. We
suggest either mandating that
<code class="sourceCode default">ignore</code>’s type not be a template,
or finding a way to leave it unspecified.</p>
<p>However, may be LEWG will decide on being more specific and less
hand-wavy on the semantics of the type underlying
<code class="sourceCode default">std::ignore</code> and even follow the
suggestion to move its definition into another header
(<code class="sourceCode default">&lt;utility&gt;</code> or
<code class="sourceCode default">&lt;ignore&gt;</code>).</p>
<p>The mailing list discussion seems to favor making it available
through <code class="sourceCode default">&lt;utility&gt;</code> as well
to <code class="sourceCode default">&lt;tuple&gt;</code>, as is
<code class="sourceCode default">std::tuple_size</code>, for
example.</p>
<h1 data-number="8" id="wording"><span class="header-section-number">8</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>In <a href="https://eel.is/c++draft/tuple.syn">tuple.syn</a> change
the type of ignore from “unspecified” to an exposition-only type</p>
<div>
<div class="sourceCode" id="cb5"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="va">+// [utility.ignore], ignore</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="va">+struct <em>ignore_t</em> { // <em>exposition only</em></span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="va">+  constexpr const <em>ignore_t</em>&amp;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="va">+    operator=(auto&amp;&amp;) const &amp; noexcept</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="va">+      { return *this; }</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="va">+};</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="va">+inline constexpr <em>ignore_type</em> ignore;</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>// 22.4.5, tuple creation functions</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="st">-inline constexpr <em>unspecified</em> ignore;</span></span></code></pre></div>
</div>
<p>In <a href="https://eel.is/c++draft/tuple.creation">tuple.creation</a>, remove
the normative text about
<code class="sourceCode default">ignore</code>:</p>
<div>
<div class="sourceCode" id="cb6"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a> template&lt;class... TTypes&gt;</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>   constexpr tuple&lt;TTypes&amp;...&gt; tie(TTypes&amp;... t) noexcept;</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> 5. Returns: tuple&lt;TTypes&amp;...&gt;(t...).</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="st">-When an argument in t is ignore, assigning any value to the corresponding tuple element has no effect.</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> 6. [Example 2: tie functions allow one to create tuples that unpack tuples into variables.</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> ignore can be used for elements that are not needed:</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>     int i; std::string s;</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>     tie(i, ignore, s) = make_tuple(42, 3.14, "C++");</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>     // i == 42, s == "C++"</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a> — end example]</span></code></pre></div>
</div>
<p>In <a href="https://eel.is/c++draft/utility.syn">utility.syn</a>, add
<code class="sourceCode default">ignore</code> to the
<code class="sourceCode default">&lt;utility&gt;</code> header also:</p>
<div>
<div class="sourceCode" id="cb7"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a> template&lt;class... T&gt;</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>   using index_sequence_for = make_index_sequence&lt;sizeof...(T)&gt;;</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="va">+// [utility.ignore], ignore</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="va">+struct <em>ignore_t</em> { // <em>exposition only</em></span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="va">+  constexpr const <em>ignore_t</em>&amp;</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a><span class="va">+    operator=(auto&amp;&amp;) const &amp; noexcept</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="va">+      { return *this; }</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="va">+};</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="va">+inline constexpr <em>ignore_t</em> ignore;</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a> // [pairs], class template pair</span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a> template&lt;class T1, class T2&gt;</span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>   struct pair;</span></code></pre></div>
</div>
<p>We don’t think a feature-test macro is required for this patch, as
it’s just barely visible to the programmer, and there is no situation
where the programmer would want to do something different based on the
absence of the feature.</p>
<h1 data-number="9" id="references"><span class="header-section-number">9</span> References<a href="#references" class="self-link"></a></h1>
<ul>
<li><a href="https://wg21.link/lwg2933">LWG 2933</a></li>
<li><a href="https://wg21.link/lwg3978">LWG 3978</a></li>
<li>The markdown of this document is available at my <a href="https://raw.githubusercontent.com/PeterSommerlad/SC22WG21_Papers/master/drafting/P2968Rx_ignore.md">github</a></li>
</ul>
</div>
</div>


</body></html>