<!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-03-20" />
  <title>`std::const_iterator` often produces an unexpected type</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"><code class="sourceCode default">std::const_iterator</code>
often produces an unexpected type</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2836R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2023-03-20</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>
      Ranges Study Group (SG9)<br>
      Library Evolution Working Group (LEWG)<br>
      Library Working Group (LWG)<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Christopher Di Bella<br>&lt;<a href="mailto:cjdb@google.com" class="email">cjdb@google.com</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="#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">2</span>
Acknowledgements<span></span></a></li>
<li><a href="#problem" id="toc-problem"><span class="toc-section-number">3</span> Problem<span></span></a>
<ul>
<li><a href="#potential-backwards-compatibility-issues" id="toc-potential-backwards-compatibility-issues"><span class="toc-section-number">3.1</span> Potential backwards compatibility
issues<span></span></a></li>
<li><a href="#template-instantiation-issue" id="toc-template-instantiation-issue"><span class="toc-section-number">3.2</span> Template instantiation
issue<span></span></a></li>
<li><a href="#didnt-p2278-note-some-complexities" id="toc-didnt-p2278-note-some-complexities"><span class="toc-section-number">3.3</span> Didn’t P2278 note some
complexities?<span></span></a></li>
</ul></li>
<li><a href="#potential-resolutions" id="toc-potential-resolutions"><span class="toc-section-number">4</span>
Potential resolutions<span></span></a>
<ul>
<li><a href="#const_iterator_for" id="toc-const_iterator_for"><span class="toc-section-number">4.1</span>
<code class="sourceCode default">const_iterator_for</code><span></span></a>
<ul>
<li><a href="#alternative-names" id="toc-alternative-names"><span class="toc-section-number">4.1.1</span> Alternative
names<span></span></a></li>
</ul></li>
<li><a href="#preferred-resolution" id="toc-preferred-resolution"><span class="toc-section-number">4.2</span> Preferred
resolution<span></span></a>
<ul>
<li><a href="#impact-on-abi" id="toc-impact-on-abi"><span class="toc-section-number">4.2.1</span> Impact on
ABI<span></span></a></li>
</ul></li>
<li><a href="#alternative-resolution" id="toc-alternative-resolution"><span class="toc-section-number">4.3</span> Alternative
resolution<span></span></a></li>
<li><a href="#changes-to-rangescbegin" id="toc-changes-to-rangescbegin"><span class="toc-section-number">4.4</span> Changes to
<code class="sourceCode default">ranges::cbegin</code><span></span></a></li>
</ul></li>
<li><a href="#why-is-this-being-identified-now" id="toc-why-is-this-being-identified-now"><span class="toc-section-number">5</span> Why is this being identified
<em>now</em>?<span></span></a></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">6</span> Implementation
experience<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">7</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p><code class="sourceCode default">const_iterator&lt;T&gt;</code> is
too aggressive in what it turns into a
<code class="sourceCode default">basic_const_iterator&lt;T&gt;</code>,
and it creates inconsistencies. This proposal scales it back.</p>
<h1 data-number="2" id="acknowledgements"><span class="header-section-number">2</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Thank you to Richard Smith, Janet Cobb, Nicole Mazzuca, and David
Blaikie for providing feedback on the text and design of the proposed
resolution.</p>
<p>Thank you to Nicole and Stephan T. Lavavej (STL) for reviewing the CL
that implements the proposed fix in my Microsoft/STL fork.</p>
<h1 data-number="3" id="problem"><span class="header-section-number">3</span> Problem<a href="#problem" class="self-link"></a></h1>
<p><span class="citation" data-cites="P2278R4">[<a href="#ref-P2278R4" role="doc-biblioref">P2278R4</a>]</span> defined
<code class="sourceCode default">const_iterator&lt;int*&gt;</code> to be
<code class="sourceCode default">basic_const_iterator&lt;int*&gt;</code>
instead of <code class="sourceCode default">int const*</code>, because
it seeks to simplify the implementation of esoteric ranges, even though
this comes at the expense of more conventional use-cases. As a result,
determining the corresponding “const iterator” for an iterator is
context-dependent and inconsistent, which is surprising to both the
author, some experts, and even implementers. Consider the following
snippet of code:</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">using</span> V <span class="op">=</span> std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span>;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> v <span class="op">=</span> V<span class="op">()</span>;</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> I1 <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>cbegin<span class="op">(</span>v<span class="op">))</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> I2 <span class="op">=</span> ranges<span class="op">::</span>const_iterator_t<span class="op">&lt;</span>V<span class="op">&gt;</span>;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>same_as<span class="op">&lt;</span>I1, I2<span class="op">&gt;)</span>;</span></code></pre></div>
<p>That static assert fails because
<code class="sourceCode default">I1</code> is the type
<code class="sourceCode default">V::const_iterator</code>, while
<code class="sourceCode default">I2</code> has the type <code class="sourceCode default">basic_const_iterator&lt;V::iterator&gt;</code>.
While the pointer situation is surprising, there is some wiggle room in
arguing that C++’s standard library being somewhat quirky. This crosses
that line because <code class="sourceCode default">ranges::iterator_t&lt;R const&gt;</code> and
<code class="sourceCode default">ranges::const_iterator_t&lt;R&gt;</code>
ought to be analogous: it is fairly reasonable for someone to conclude
that because <code class="sourceCode default">decltype(std::as_const(vec).begin())</code>
and <code class="sourceCode default">decltype(vec.cbegin())</code> are
the same type, so too should <code class="sourceCode default">decltype(ranges::begin(std::as_const(vec)))</code>
and
<code class="sourceCode default">decltype(ranges::cbegin(vec))</code>.</p>
<p>A third example:</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="kw">using</span> S <span class="op">=</span> ranges<span class="op">::</span>subrange<span class="op">&lt;</span>V<span class="op">::</span>iterator<span class="op">&gt;</span>;</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> s <span class="op">=</span> S<span class="op">(</span>v<span class="op">.</span>begin<span class="op">()</span>, v<span class="op">.</span>end<span class="op">())</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> I3 <span class="op">=</span> ranges<span class="op">::</span>const_iterator_t<span class="op">&lt;</span>S<span class="op">&gt;</span>;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>same_as<span class="op">&lt;</span>I1, I3<span class="op">&gt;)</span>;</span></code></pre></div>
<p>Again, this fails because <code class="sourceCode default">I3</code>
ends up with the same type as
<code class="sourceCode default">I2</code>.</p>
<p>I think all of these situations are far more likely to be encountered
(and more common) than P2278’s
<code class="sourceCode default">zstring</code> example. Since
<code class="sourceCode default">zstring</code> has an esoteric
implementation, it should equally have an esoteric solution.</p>
<h2 data-number="3.1" id="potential-backwards-compatibility-issues"><span class="header-section-number">3.1</span> Potential backwards
compatibility issues<a href="#potential-backwards-compatibility-issues" class="self-link"></a></h2>
<p>This problem was discovered while writing a test for
<code class="sourceCode default">ranges::const_iterator_t</code>.</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">class</span> always_const_range <span class="op">{</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span><span class="op">*</span> begin<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span><span class="op">*</span> end<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>It was surprising to me that <code class="sourceCode default">ranges::const_iterator_t&lt;always_const_range&gt;</code>
returned anything other than a pointer, which is the case for C++20. The
type does change regardless, but changing from a pointer to a class
template is a much larger change that can affect specialisations and
possibly even some overload resolution.</p>
<p>Another potential problem is this:</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="kw">class</span> a_range <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  my<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;::</span>iterator begin<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  my<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;::</span>iterator end<span class="op">()</span> <span class="kw">const</span>;</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> a_function<span class="op">(</span>my<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;::</span>const_iterator<span class="op">)</span>;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="co">// ...</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="co">// Works in C++20, breaks in C++23.</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="kw">const</span> r <span class="op">=</span> a_range<span class="op">()</span>;</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>a_function<span class="op">(</span>ranges<span class="op">::</span>cbegin<span class="op">(</span>r<span class="op">))</span>;</span></code></pre></div>
<p>In the above code,
<code class="sourceCode default">my::vector::iterator</code> can be
implicitly converted to
<code class="sourceCode default">my::vector::const_iterator</code> as
has been a convention since at least C++11. Since
<code class="sourceCode default">basic_const_iterator</code> doesn’t
appear to have a conversion operator to
<code class="sourceCode default">my::vector::const_iterator</code>,
however, it’s not necessarily possible for
<code class="sourceCode default">a_function</code> to be called without
making an intrusive change to the call site (we can tack on
<code class="sourceCode default">.base()</code>) or
<code class="sourceCode default">my::vector::const_iterator</code>. In
cases where the user isn’t also the owner, this mightn’t be
possible.</p>
<h2 data-number="3.2" id="template-instantiation-issue"><span class="header-section-number">3.2</span> Template instantiation issue<a href="#template-instantiation-issue" class="self-link"></a></h2>
<p>Here’s how template instantiation is affected.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> c1<span class="op">(</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span> v, <span class="dt">int</span> <span class="kw">const</span> value<span class="op">)</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">// calls ranges::find&lt;vector&lt;int&gt;::const_iterator, vector&lt;int&gt;::const_iterator, int&gt;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> ranges<span class="op">::</span>find<span class="op">(</span>v, value<span class="op">)</span> <span class="op">!=</span> v<span class="op">.</span>end<span class="op">()</span>;</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> c2<span class="op">(</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span> v, <span class="dt">int</span> <span class="kw">const</span> value<span class="op">)</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>  <span class="co">// calls ranges::find&lt;vector&lt;int&gt;::const_iterator, vector&lt;int&gt;::const_iterator, int&gt;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> ranges<span class="op">::</span>find<span class="op">(</span>v<span class="op">.</span>cbegin<span class="op">()</span>, v<span class="op">.</span>cend<span class="op">()</span>, <span class="dv">1</span><span class="op">)</span> <span class="op">!=</span> v<span class="op">.</span>end<span class="op">()</span>;</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> c3<span class="op">(</span>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span> v, <span class="dt">int</span> <span class="kw">const</span> value<span class="op">)</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>  <span class="co">// calls ranges::find&lt;basic_const_iterator&lt;vector&lt;int&gt;::iterator&gt;, basic_const_iterator&lt;vector&lt;int&gt;::iterator&gt;, int&gt;</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> ranges<span class="op">::</span>find<span class="op">(</span>ranges<span class="op">::</span>cbegin<span class="op">(</span>v<span class="op">)</span>, ranges<span class="op">::</span>end<span class="op">(</span>v<span class="op">)</span>, value<span class="op">)</span> <span class="op">!=</span> ranges<span class="op">::</span>cend<span class="op">(</span>v<span class="op">)</span>;</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Despite <code class="sourceCode default">c1</code> and
<code class="sourceCode default">c2</code> both making a call to a
standardised entity named
<code class="sourceCode default">cbegin</code>, they’re getting back
different types, and thus instantiating different specialisations of
<code class="sourceCode default">ranges::find</code>. Not only is it
surprising, but it will also lead to increased program sizes and
compilation slowdowns.</p>
<h2 data-number="3.3" id="didnt-p2278-note-some-complexities"><span class="header-section-number">3.3</span> Didn’t P2278 note some
complexities?<a href="#didnt-p2278-note-some-complexities" class="self-link"></a></h2>
<p>P2278 talks about <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2278r4.html#customizing-make_const_iterator:~:text=We%20could%20add%20complexity%20to%20make_const_sentinel">adding
complexity to <code class="sourceCode default">zstring</code> by
introducing a
<code class="sourceCode default">const_zsentinel</code></a> that opens
itself up to being comparable with arbitrary pointers, and that by going
down this route we’d need to introduce a
<code class="sourceCode default">const_iterator_cast</code> since
<code class="sourceCode default">const_cast</code> only applies to
pointers in this context. P2278 doesn’t expand on why that’s not
desirable, but it’s probably safe to conclude that it’s for the same
reasons we consider <code class="sourceCode default">const_cast</code>
to be icky. At least, that’s why I don’t like it: we shouldn’t be giving
folks more opportunities to cast away constness.</p>
<p>P2278 also talks about <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2278r4.html#customizing-make_const_iterator:~:text=Let%E2%80%99s%20instead%20consider%20adding%20complexity%20in%20the%20other%20direction%2C%20to%20make_const_iterator">putting
the burden on
<code class="sourceCode default">make_const_iterator</code></a>, which
can intelligently discern between already constant iterators, pointers,
and other types. It <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2278r4.html#:~:text=I%E2%80%99m%20not%20sure%20it%E2%80%99s%20worth%20it.%20The%20simpler%20design%20is%20easier%20to%20understand.">argues
that this design is more complex and implies it’s harder to
understand</a>. While this does make it easy to understand in a vacuum,
the above cases have identified a variety of issues that can crop up in
practical code, leading to potential confusion at point-of-use.</p>
<h1 data-number="4" id="potential-resolutions"><span class="header-section-number">4</span> Potential resolutions<a href="#potential-resolutions" class="self-link"></a></h1>
<p>There are two ways in which we can fix this issue. Both of them
require introducing an opt-in mechanism for detecting an iterator’s
corresponding <code class="sourceCode default">const_iterator</code>.
This can be detected using an associated type such as
<code class="sourceCode default">const_iterator_for</code> below.</p>
<h2 data-number="4.1" id="const_iterator_for"><span class="header-section-number">4.1</span>
<code class="sourceCode default">const_iterator_for</code><a href="#const_iterator_for" class="self-link"></a></h2>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span>input_iterator<span class="op">&gt;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> const_iterator_for <span class="op">{}</span>;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span>input_iterator I<span class="op">&gt;</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> const_iterator_for<span class="op">&lt;</span><span class="kw">const</span> I<span class="op">&gt;</span> <span class="op">:</span> const_iterator_for<span class="op">&lt;</span>I<span class="op">&gt;</span> <span class="op">{}</span>;</span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span>input_iterator I<span class="op">&gt;</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> is_pointer_v<span class="op">&lt;</span>I<span class="op">&gt;</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> const_iterator_for<span class="op">&lt;</span>I<span class="op">&gt;</span> <span class="op">{</span> <span class="kw">using</span> type <span class="op">=</span> <span class="kw">const</span> remove_pointer_t<span class="op">&lt;</span>T<span class="op">&gt;*</span>; <span class="op">}</span>;</span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span>input_iterator I<span class="op">&gt;</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">{</span> <span class="kw">typename</span> I<span class="op">::</span>const_iterator_for; <span class="op">}</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> const_iterator_for<span class="op">&lt;</span>I<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> type <span class="op">=</span> <span class="kw">typename</span> I<span class="op">::</span>const_iterator_for;</span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span>input_iterator I<span class="op">&gt;</span></span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">{</span> <span class="kw">typename</span> const_iterator_for<span class="op">&lt;</span>I<span class="op">&gt;::</span>type; <span class="op">}</span></span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> const_iterator_for_t <span class="op">=</span> <span class="kw">typename</span> const_iterator_for<span class="op">&lt;</span>I<span class="op">&gt;::</span>type;</span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Then, for example,
<code class="sourceCode default">std::vector&lt;int&gt;::iterator</code>
could identify that <code class="sourceCode default">std::vector&lt;int&gt;::const_iterator</code>
is its <code class="sourceCode default">const_iterator</code>
counterpart by adding
<code class="sourceCode default">const_iterator_for</code> as a
member-alias. The formal wording for
<code class="sourceCode default">const_iterator_for</code> requires
touching all the iterators in the standard library, which is a laborious
task. This will be added once there’s general LEWG approval for the
paper (and will be added no later than the weekend after
discussion).</p>
<p>A more conservative option would be for
<code class="sourceCode default">const_iterator_for</code> to be an
exposition-only type that works for pointers, but not class types. There
are two reasons to consider this: it’s more clearly within the scope of
a DR, and it doesn’t require introducing a new customisation mechanism
that impacts the standard library and user code. This is a cost/benefit
trade-off: a large portion of the benefits are concerned with handling
pointers better, while the cost comes from handling the other cases.
This is a halfway measure that is worth considering if folks find the
full solution too much for a retroactive fix.</p>
<h3 data-number="4.1.1" id="alternative-names"><span class="header-section-number">4.1.1</span> Alternative names<a href="#alternative-names" class="self-link"></a></h3>
<p>The original name for
<code class="sourceCode default">const_iterator_for</code> was
<code class="sourceCode default">const_iterator_counterpart</code>.
Another potential name might be
<code class="sourceCode default">const_iterator_is</code>.</p>
<h2 data-number="4.2" id="preferred-resolution"><span class="header-section-number">4.2</span> Preferred resolution<a href="#preferred-resolution" class="self-link"></a></h2>
<p>The preferred resolution would be to rework
<code class="sourceCode default">const_iterator</code> so it only uses
<code class="sourceCode default">basic_const_iterator</code> when
<code class="sourceCode default">const_iterator_for_t&lt;I&gt;</code>
isn’t valid. The following change should be made to
[const.iterators.alias]:</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;input_iterator I&gt;</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>    using const_iterator = <em>see below</em>;</span></code></pre></div>
</div>
<div class="rm" style="color: #bf0303">
<p><em>Result</em>: If <code class="sourceCode default">I</code> models
<em><code class="sourceCode default">constant-iterator</code></em>,
<code class="sourceCode default">I</code>. Otherwise,
<code class="sourceCode default">basic_const_iterator&lt;I&gt;</code>.</p>
</div>
<div class="add" style="color: #006e28">
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Result</em>: If:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code class="sourceCode default">I</code> models
<em><code class="sourceCode default">constant-iterator</code></em>,
<code class="sourceCode default">I</code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
Otherwise, if
<code class="sourceCode default">const_iterator_for_t&lt;I&gt;</code> is
well-formed,
<code class="sourceCode default">const_iterator_for_t&lt;I&gt;</code>;</li>
<li><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
Otherwise,
<code class="sourceCode default">basic_const_iterator&lt;I&gt;</code>.</li>
</ul>

</div>
<h3 data-number="4.2.1" id="impact-on-abi"><span class="header-section-number">4.2.1</span> Impact on ABI<a href="#impact-on-abi" class="self-link"></a></h3>
<p>STL from the Microsoft/STL team has noted that changing
<code class="sourceCode default">std::const_iterator</code> now will be
an ABI break because it tries to revise a conscious design choice, and
isn’t personally convinced that it’s worth doing. Nicole pointed out
that it’s not a “full” ABI break since Microsoft hasn’t yet released an
ABI-stable version. My understanding is that this means that we’re not
yet at the point-of-no-return, although that date is fast
approaching.</p>
<h2 data-number="4.3" id="alternative-resolution"><span class="header-section-number">4.3</span> Alternative resolution<a href="#alternative-resolution" class="self-link"></a></h2>
<p>An alternative resolution is to add <code class="sourceCode default">explicit(false) operator const_iterator_for_t&lt;I&gt;() const</code>
to <code class="sourceCode default">basic_const_iterator</code>. This is
a more conservative option that I’m less partial to due to it not
solving all the issues, but at least it means that
<code class="sourceCode default">basic_const_iterator</code> can play
with const iterators.</p>
<h2 data-number="4.4" id="changes-to-rangescbegin"><span class="header-section-number">4.4</span> Changes to
<code class="sourceCode default">ranges::cbegin</code><a href="#changes-to-rangescbegin" class="self-link"></a></h2>
<p>P2278 raises the concern that
<code class="sourceCode default">cbegin</code> shouldn’t produce an
iterator that is incompatible with the sentinel produced by
<code class="sourceCode default">cend</code>. This is something that I
absolutely agree with. Any change to the status quo should not result in
an incompatibility between the two. Although
<code class="sourceCode default">ranges::cbegin(r)</code> can be
evaluated even when
<code class="sourceCode default">ranges::end(r)</code> can’t be,
<code class="sourceCode default">ranges::cbegin(r)</code>’s behaviour is
tied to whether or not
<code class="sourceCode default">ranges::end(r)</code> is allowed, and
what it returns. That is, we only map from
<code class="sourceCode default">R</code> to
<code class="sourceCode default">R const</code> if
<code class="sourceCode default">R const</code> is a constant range when
<code class="sourceCode default">R</code> is not: being able to detect
that <code class="sourceCode default">R const</code> is a constant range
depends on <code class="sourceCode default">ranges::end(r)</code> being
well-formed. A potential way to skirt the issue at the start of this
paragraph is to change
<code class="sourceCode default">ranges::cbegin</code> to also do the
same thing for <code class="sourceCode default">ranges::end</code>,
except when <code class="sourceCode default">ranges::end(r)</code>
produces a sentinel already compatible with
<code class="sourceCode default">const_iterator&lt;I&gt;</code>.</p>
<p>Changes to [range.access.cbegin]:</p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The name <code class="sourceCode default">ranges​::​cbegin</code> denotes
a customization point object ([customization.point.object]). Given a
subexpression <code class="sourceCode default">E</code> with type
<code class="sourceCode default">T</code>, let
<code class="sourceCode default">t</code> be an lvalue that denotes the
reified object for <code class="sourceCode default">E</code>. Then:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> If
<code class="sourceCode default">E</code> is an rvalue and <code class="sourceCode default">enable_borrowed_range&lt;remove_cv_t&lt;T&gt;&gt;</code>
is false, <code class="sourceCode default">ranges​::​cbegin(E)</code> is
ill-formed.</li>
</ul>
<div class="add" style="color: #006e28">

<ul>
<li><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
Otherwise, let <code class="sourceCode default">U</code> be <code class="sourceCode default">ranges::begin(<em>possibly-const-range</em>(t))</code>.
If neither <code class="sourceCode default">ranges::end(<em>possibly-const-range</em>(t))</code>
nor <code class="sourceCode default">ranges::end(t)</code> are a valid
expressions whose respective types model
<code class="sourceCode default">sentinel_for&lt;I&gt;</code>, then
<code class="sourceCode default">ranges::cbegin(E)</code> is
ill-formed.</li>
</ul>

</div>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
Otherwise, <code class="sourceCode default">ranges​::​cbegin(E)</code> is
expression-equivalent to <code class="sourceCode default">const_iterator&lt;decltype(U)&gt;(U)</code>.</li>
</ul>
<h1 data-number="5" id="why-is-this-being-identified-now"><span class="header-section-number">5</span> Why is this being identified
<em>now</em>?<a href="#why-is-this-being-identified-now" class="self-link"></a></h1>
<p>This originally started out as a defect report to LWG that was issued
on 2023-02-09, while I was implementng a C++23-friendly
<code class="sourceCode default">ranges::cbegin</code>. I also
investigated whether there would be a second round of NB ballot
comments, but it seems that the committee is quickly moving toward an
FDIS ballot.</p>
<p>This is incredibly late in the game, but the only implementation to
have shipped <code class="sourceCode default">std::const_iterator</code>
is either Visual Studio 2022 17.5 or 17.6, both of which are 2023
releases (the feature was in review from August through October 2022
according to <a href="https://github.com/microsoft/STL/pull/3043">Microsoft/STL#3043</a>).
This means that there was little implementation experience during the
C++23 cycle, and next to no deployment experience at scale within that
timeframe. Avoiding this in the future, however, should be discussed in
a separate paper<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a>. We should aim to fix any identified
issues as quickly as possible, and also work out a way to prevent this
from happening in any future iterations of C++ standardisation.</p>
<h1 data-number="6" id="implementation-experience"><span class="header-section-number">6</span> Implementation experience<a href="#implementation-experience" class="self-link"></a></h1>
<p>The above design has been integrated into a Microsoft/STL <a href="https://github.com/cjdb/Microsoft-STL/pull/1">branch</a> and has
been reviewed by two people on the Microsoft/STL team.</p>
<h1 data-number="7" id="bibliography"><span class="header-section-number">7</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-P2278R4" class="csl-entry" role="doc-biblioentry">
[P2278R4] Barry Revzin. 2022-06-17. cbegin should always return a
constant iterator. <a href="https://wg21.link/p2278r4"><div class="csl-block">https://wg21.link/p2278r4</div></a>
</div>
</div>
<section class="footnotes footnotes-end-of-document" role="doc-endnotes">
<hr />
<ol>
<li id="fn1" role="doc-endnote"><p>The irony of this paper’s proposed
fixes having at most as much implementation and deployment experience as
P2278R4 is not lost on me.<a href="#fnref1" class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</section>
</div>
</div>
</body>
</html>
