<!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="2025-06-18" />
  <title>A Sentinel for Null-Terminated Strings</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">A Sentinel for
Null-Terminated Strings</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3705R2</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-06-18</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>
      SG-9 Ranges<br>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Eddie Nolan<br>&lt;<a href="mailto:eddiejnolan@gmail.com" class="email">eddiejnolan@gmail.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="#motivation" id="toc-motivation"><span class="toc-section-number">1</span> Motivation<span></span></a></li>
<li><a href="#naming-discussion" id="toc-naming-discussion"><span class="toc-section-number">2</span> Naming discussion<span></span></a>
<ul>
<li><a href="#bad-names" id="toc-bad-names"><span class="toc-section-number">2.1</span> Bad names<span></span></a>
<ul>
<li><a href="#c_str" id="toc-c_str"><span class="toc-section-number">2.1.1</span>
<code class="sourceCode cpp">c_str</code><span></span></a></li>
<li><a href="#zstring_sentinel-and-zstring" id="toc-zstring_sentinel-and-zstring"><span class="toc-section-number">2.1.2</span>
<code class="sourceCode cpp">zstring_sentinel</code> and
<code class="sourceCode cpp">zstring</code><span></span></a></li>
</ul></li>
<li><a href="#good-names" id="toc-good-names"><span class="toc-section-number">2.2</span> Good names<span></span></a>
<ul>
<li><a href="#status-quo-null_sentinel-and-null_term" id="toc-status-quo-null_sentinel-and-null_term"><span class="toc-section-number">2.2.1</span> Status quo:
<code class="sourceCode cpp">null_sentinel</code> and
<code class="sourceCode cpp">null_term</code><span></span></a></li>
<li><a href="#zero_termination_sentinel" id="toc-zero_termination_sentinel"><span class="toc-section-number">2.2.2</span>
<code class="sourceCode cpp">zero_termination_sentinel</code><span></span></a></li>
<li><a href="#your-suggestion-here" id="toc-your-suggestion-here"><span class="toc-section-number">2.2.3</span> Your suggestion
here<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">3</span> Wording<span></span></a>
<ul>
<li><a href="#exposition-only-helper-concept-default-initializable-and-equality-comparable-iter-value" id="toc-exposition-only-helper-concept-default-initializable-and-equality-comparable-iter-value"><span class="toc-section-number">3.1</span> Exposition-only helper concept
<code class="sourceCode cpp"><em>default-initializable-and-equality-comparable-iter-value</em></code><span></span></a></li>
<li><a href="#null-sentinel" id="toc-null-sentinel"><span class="toc-section-number">3.2</span> Null sentinel<span></span></a>
<ul>
<li><a href="#operations" id="toc-operations"><span class="toc-section-number">3.2.1</span> Operations<span></span></a></li>
</ul></li>
<li><a href="#null_term-cpo" id="toc-null_term-cpo"><span class="toc-section-number">3.3</span>
<code class="sourceCode cpp">null_term</code> CPO<span></span></a></li>
<li><a href="#feature-test-macro" id="toc-feature-test-macro"><span class="toc-section-number">3.4</span> Feature test
macro<span></span></a></li>
</ul></li>
<li><a href="#history" id="toc-history"><span class="toc-section-number">4</span> History<span></span></a>
<ul>
<li><a href="#changelog" id="toc-changelog"><span class="toc-section-number">4.1</span> Changelog<span></span></a>
<ul>
<li><a href="#changes-since-p2728r1" id="toc-changes-since-p2728r1"><span class="toc-section-number">4.1.1</span> Changes since
P2728R1<span></span></a></li>
<li><a href="#changes-since-p2728r3" id="toc-changes-since-p2728r3"><span class="toc-section-number">4.1.2</span> Changes since
P2728R3<span></span></a></li>
<li><a href="#changes-since-p2728r4" id="toc-changes-since-p2728r4"><span class="toc-section-number">4.1.3</span> Changes since
P2728R4<span></span></a></li>
<li><a href="#changes-since-p2728r5" id="toc-changes-since-p2728r5"><span class="toc-section-number">4.1.4</span> Changes since
P2728R5<span></span></a></li>
<li><a href="#changes-since-p2728r6" id="toc-changes-since-p2728r6"><span class="toc-section-number">4.1.5</span> Changes since
P2728R6<span></span></a></li>
<li><a href="#changes-since-p2728r7" id="toc-changes-since-p2728r7"><span class="toc-section-number">4.1.6</span> Changes since
P2728R7<span></span></a></li>
<li><a href="#changes-since-p3705r0" id="toc-changes-since-p3705r0"><span class="toc-section-number">4.1.7</span> Changes since
P3705R0<span></span></a></li>
<li><a href="#changes-since-p3705r1" id="toc-changes-since-p3705r1"><span class="toc-section-number">4.1.8</span> Changes since
P3705R1<span></span></a></li>
</ul></li>
<li><a href="#relevant-pollsminutes" id="toc-relevant-pollsminutes"><span class="toc-section-number">4.2</span> Relevant
Polls/Minutes<span></span></a>
<ul>
<li><a href="#sg9-review-of-p3705r1-on-2025-06-18-during-sofia-2025" id="toc-sg9-review-of-p3705r1-on-2025-06-18-during-sofia-2025"><span class="toc-section-number">4.2.1</span> SG9 review of P3705R1 on
2025-06-18 during Sofia 2025<span></span></a></li>
<li><a href="#sg9-review-of-d2728r4-on-2023-06-12-during-varna-2023" id="toc-sg9-review-of-d2728r4-on-2023-06-12-during-varna-2023"><span class="toc-section-number">4.2.2</span> SG9 review of D2728R4 on
2023-06-12 during Varna 2023<span></span></a></li>
<li><a href="#sg16-review-of-p2728r3-on-2023-05-10-telecon" id="toc-sg16-review-of-p2728r3-on-2023-05-10-telecon"><span class="toc-section-number">4.2.3</span> SG16 review of P2728R3 on
2023-05-10 (Telecon)<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">5</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="motivation"><span class="header-section-number">1</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p>Consider using <code class="sourceCode cpp">std<span class="op">::</span>views<span class="op">::</span>take</code>
to get the first five characters from a string. If we pass a string
literal with five or more characters, it looks okay:</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">static_assert</span><span class="op">(</span>std<span class="op">::</span>string<span class="op">{</span>std<span class="op">::</span>from_range, <span class="st">&quot;Brubeck&quot;</span> <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>take<span class="op">(</span><span class="dv">5</span><span class="op">)}</span> <span class="op">==</span> <span class="st">&quot;Brube&quot;</span><span class="op">)</span>; <span class="co">// passes</span></span></code></pre></div>
<p>However, if we pass it a string literal with fewer than five
characters, we get in trouble:</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">// static_assert(std::string{std::from_range, &quot;Dave&quot; | std::views::take(5)} == &quot;Dave&quot;); // fails</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <span class="kw">namespace</span> std<span class="op">::</span>string_view_literals;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>string<span class="op">{</span>std<span class="op">::</span>from_range, <span class="st">&quot;Dave&quot;</span> <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>take<span class="op">(</span><span class="dv">5</span><span class="op">)}</span> <span class="op">==</span> <span class="st">&quot;Dave</span><span class="sc">\0</span><span class="st">&quot;</span><span class="bu">sv</span><span class="op">)</span>; <span class="co">// passes</span></span></code></pre></div>
<p>The reason the null terminator is included in the output here is
because undecayed string literals are arrays of characters, including
the null terminator, which the ranges library treats like any other
array:</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="pp">#include </span><span class="im">&lt;algorithm&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;array&gt;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span>std<span class="op">::</span>remove_reference_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span><span class="st">&quot;foo&quot;</span><span class="op">)&gt;</span>, <span class="kw">const</span> <span class="dt">char</span><span class="op">[</span><span class="dv">4</span><span class="op">]&gt;)</span>;</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>equal<span class="op">(</span><span class="st">&quot;foo&quot;</span>, std<span class="op">::</span>array<span class="op">{</span><span class="ch">&#39;f&#39;</span>, <span class="ch">&#39;o&#39;</span>, <span class="ch">&#39;o&#39;</span>, <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">}))</span>;</span></code></pre></div>
<p>A common workaround is to wrap the string literal in <code class="sourceCode cpp">std<span class="op">::</span>string_view</code>.
But this has a performance cost: despite the fact that we only care
about the first five characters, we still need to make a pass through
the entire string to find the null terminator:</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">constexpr</span> std<span class="op">::</span>string take_five<span class="op">(</span><span class="dt">char</span> <span class="kw">const</span><span class="op">*</span> long_string<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>string_view <span class="kw">const</span> long_string_view <span class="op">=</span> long_string; <span class="co">// read all of long_string!</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> std<span class="op">::</span>string<span class="op">{</span>std<span class="op">::</span>from_range, long_string_view <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>take<span class="op">(</span><span class="dv">5</span><span class="op">)}</span>;</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This paper introduces
<code class="sourceCode cpp">null_sentinel</code> to solve this problem.
It ends the range when it encounters a null:</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="kw">constexpr</span> std<span class="op">::</span>string take_five<span class="op">(</span><span class="dt">char</span> <span class="kw">const</span><span class="op">*</span> long_string<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>ranges<span class="op">::</span>subrange <span class="kw">const</span> long_string_range<span class="op">(</span>long_string, std<span class="op">::</span>null_sentinel<span class="op">)</span>; <span class="co">// lazy!</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> std<span class="op">::</span>string<span class="op">{</span>std<span class="op">::</span>from_range, long_string_range <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>take<span class="op">(</span><span class="dv">5</span><span class="op">)}</span>;</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>It also introduces a <code class="sourceCode cpp">null_term</code>
CPO for the common case of constructing a subrange like the one in the
above example:</p>
<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">constexpr</span> std<span class="op">::</span>string take_five<span class="op">(</span><span class="dt">char</span> <span class="kw">const</span><span class="op">*</span> long_string<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> std<span class="op">::</span>string<span class="op">{</span>std<span class="op">::</span>from_range, std<span class="op">::</span>views<span class="op">::</span>null_term<span class="op">(</span>long_string<span class="op">)</span> <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>take<span class="op">(</span><span class="dv">5</span><span class="op">)}</span>;</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The sentinel type matches any iterator position
<code class="sourceCode cpp">it</code> at which
<code class="sourceCode cpp"><span class="op">*</span>it</code> is equal
to a value-initialized object of type <code class="sourceCode cpp">iter_value_t<span class="op">&lt;</span>I<span class="op">&gt;</span></code>.
This works for null-terminated strings, but can also serve as the
sentinel for any range terminated by a value-initialized value.</p>
<p>For example, <code class="sourceCode cpp">null_term</code> can be
used to iterate <code class="sourceCode cpp">argv</code> and
<code class="sourceCode cpp">environ</code>. The following program
demonstrates this:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;print&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">char</span><span class="op">**</span> environ;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">(</span><span class="dt">int</span> argc, <span class="dt">char</span><span class="op">**</span> argv<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>println<span class="op">(</span><span class="st">&quot;argv: {}&quot;</span>, std<span class="op">::</span>views<span class="op">::</span>null_term<span class="op">(</span>argv<span class="op">))</span>;</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>println<span class="op">(</span><span class="st">&quot;environ: {}&quot;</span>, std<span class="op">::</span>views<span class="op">::</span>null_term<span class="op">(</span>environ<span class="op">))</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Output:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>$ env --ignore-environment FOO=bar BAZ=quux ./test corge</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>argv: [&quot;./test&quot;, &quot;corge&quot;]</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>environ: [&quot;FOO=bar&quot;, &quot;BAZ=quux&quot;]</span></code></pre></div>
<h1 data-number="2" id="naming-discussion"><span class="header-section-number">2</span> Naming discussion<a href="#naming-discussion" class="self-link"></a></h1>
<h2 data-number="2.1" id="bad-names"><span class="header-section-number">2.1</span> Bad names<a href="#bad-names" class="self-link"></a></h2>
<h3 data-number="2.1.1" id="c_str"><span class="header-section-number">2.1.1</span>
<code class="sourceCode cpp">c_str</code><a href="#c_str" class="self-link"></a></h3>
<p><code class="sourceCode cpp">range<span class="op">-</span>v3</code>
<a href="https://ericniebler.github.io/range-v3/structranges_1_1views_1_1c__str__fn.html">provides</a>
similar functionality to <code class="sourceCode cpp">null_term</code>
using the name <code class="sourceCode cpp">c_str</code>– unlike
<code class="sourceCode cpp">null_term</code>,
<code class="sourceCode cpp">c_str</code> only works with
<code class="sourceCode cpp"><span class="dt">char</span></code>,
<code class="sourceCode cpp"><span class="dt">wchar_t</span></code>, and
so forth.</p>
<p>The name <code class="sourceCode cpp">c_str</code> would not make
sense here because, for example, <code class="sourceCode cpp">std<span class="op">::</span>views<span class="op">::</span>c_str<span class="op">(</span>argv<span class="op">)</span></code>
is nonsensical and misleading as to what the range is doing (terminating
the sequence of strings rather than terminating the strings
themselves).</p>
<h3 data-number="2.1.2" id="zstring_sentinel-and-zstring"><span class="header-section-number">2.1.2</span>
<code class="sourceCode cpp">zstring_sentinel</code> and
<code class="sourceCode cpp">zstring</code><a href="#zstring_sentinel-and-zstring" class="self-link"></a></h3>
<p>An example from Barry Revzin’s <span class="citation" data-cites="P2210R2">[<a href="https://wg21.link/p2210r2" role="doc-biblioref">P2210R2</a>]</span> provides similar functionality
under the names <code class="sourceCode cpp">zstring_sentinel</code> and
<code class="sourceCode cpp">zstring</code>.</p>
<p>I dislike this name for similar reasons as
<code class="sourceCode cpp">c_str</code>.
<code class="sourceCode cpp">argv</code> is not a “string.”</p>
<p>Additionally, it invites confusion with <span class="citation" data-cites="P3655R1">[<a href="#ref-P3655R1" role="doc-biblioref"><strong>P3655R1?</strong></a>]</span>
<code class="sourceCode cpp">zstring_view</code>.</p>
<h2 data-number="2.2" id="good-names"><span class="header-section-number">2.2</span> Good names<a href="#good-names" class="self-link"></a></h2>
<h3 data-number="2.2.1" id="status-quo-null_sentinel-and-null_term"><span class="header-section-number">2.2.1</span> Status quo:
<code class="sourceCode cpp">null_sentinel</code> and
<code class="sourceCode cpp">null_term</code><a href="#status-quo-null_sentinel-and-null_term" class="self-link"></a></h3>
<p>The advantages of these names are that they are terse, they do not
include the word “string,” and the value-initialized
<code class="sourceCode cpp">iter_value_t</code> value is referred to as
“null,” which reflects the language we use in the standard (“null
terminated byte string,” “null terminated multibyte string,” “null
terminated character sequence,” “null pointer”)</p>
<h3 data-number="2.2.2" id="zero_termination_sentinel"><span class="header-section-number">2.2.2</span>
<code class="sourceCode cpp">zero_termination_sentinel</code><a href="#zero_termination_sentinel" class="self-link"></a></h3>
<p>This is used by think-cell’s <a href="https://github.com/think-cell/think-cell-library/blob/main/tc%2Frange%2Fmeta.h#L248">implementation</a>
of this utility. I like it slightly less because it’s more verbose but
also consider it acceptable.</p>
<h3 data-number="2.2.3" id="your-suggestion-here"><span class="header-section-number">2.2.3</span> Your suggestion here<a href="#your-suggestion-here" class="self-link"></a></h3>
<p>This is not an exhaustive list.</p>
<h1 data-number="3" id="wording"><span class="header-section-number">3</span> Wording<a href="#wording" class="self-link"></a></h1>
<h2 data-number="3.1" id="exposition-only-helper-concept-default-initializable-and-equality-comparable-iter-value"><span class="header-section-number">3.1</span> Exposition-only helper concept
<code class="sourceCode cpp"><em>default-initializable-and-equality-comparable-iter-value</em></code><a href="#exposition-only-helper-concept-default-initializable-and-equality-comparable-iter-value" class="self-link"></a></h2>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> I<span class="op">&gt;</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">concept</span> <em>default-initializable-and-equality-comparable-iter-value</em> <span class="op">=</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    default_initializable<span class="op">&lt;</span>iter_value_t<span class="op">&lt;</span>I<span class="op">&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>    equality_comparable_with<span class="op">&lt;</span>iter_reference_t<span class="op">&lt;</span>I<span class="op">&gt;</span>, iter_value_t<span class="op">&lt;</span>I<span class="op">&gt;&gt;</span>; <span class="co">// <em>exposition only</em></span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="3.2" id="null-sentinel"><span class="header-section-number">3.2</span> Null sentinel<a href="#null-sentinel" class="self-link"></a></h2>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> null_sentinel_t <span class="op">{</span></span>
<span id="cb10-4"><a href="#cb10-4" 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="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>      <span class="kw">requires</span> <em>default-initializable-and-equality-comparable-iter-value</em><span class="op">&lt;</span>I<span class="op">&gt;</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>I <span class="kw">const</span><span class="op">&amp;</span> it, null_sentinel_t<span class="op">)</span>;</span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">inline</span> <span class="kw">constexpr</span> null_sentinel_t null_sentinel;</span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="3.2.1" id="operations"><span class="header-section-number">3.2.1</span> Operations<a href="#operations" class="self-link"></a></h3>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" 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="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <em>default-initializable-and-equality-comparable-iter-value</em><span class="op">&lt;</span>I<span class="op">&gt;</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>I <span class="kw">const</span><span class="op">&amp;</span> it, null_sentinel_t<span class="op">)</span>;</span></code></pre></div>
<p>Effects:</p>
<p>Equivalent to <code class="sourceCode cpp"><span class="cf">return</span> <span class="op">*</span>it <span class="op">==</span> iter_value_t<span class="op">&lt;</span>I<span class="op">&gt;()</span>;</code>.</p>
<h2 data-number="3.3" id="null_term-cpo"><span class="header-section-number">3.3</span>
<code class="sourceCode cpp">null_term</code> CPO<a href="#null_term-cpo" class="self-link"></a></h2>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std<span class="op">::</span>views <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">inline</span> <span class="kw">constexpr</span> <em>unspecified</em> null_term;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The name <code class="sourceCode cpp">null_term</code> denotes a
customization point object ([customization.point.object]). Given a
subexpression <code class="sourceCode cpp">E</code>, the expression
<code class="sourceCode cpp">null_term<span class="op">(</span>E<span class="op">)</span></code>
is expression-equivalent to <code class="sourceCode cpp">ranges<span class="op">::</span>subrange<span class="op">(</span>E, null_sentinel<span class="op">)</span></code>.</p>
<h2 data-number="3.4" id="feature-test-macro"><span class="header-section-number">3.4</span> Feature test macro<a href="#feature-test-macro" class="self-link"></a></h2>
<p>Header <code class="sourceCode cpp"><span class="op">&lt;</span>version<span class="op">&gt;</span></code>
synopsis [version.syn]</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#define __cpp_lib_ranges_null_sentinel </span><span class="dv">2026</span><span class="er">XXL</span></span></code></pre></div>
<h1 data-number="4" id="history"><span class="header-section-number">4</span> History<a href="#history" class="self-link"></a></h1>
<h2 data-number="4.1" id="changelog"><span class="header-section-number">4.1</span> Changelog<a href="#changelog" class="self-link"></a></h2>
<p>This proposal was originally written by Zach Laine as part of <span class="citation" data-cites="P2728R0">[<a href="https://wg21.link/p2728r0" role="doc-biblioref">P2728R0</a>]</span>, then updated and split out by
Eddie Nolan.</p>
<h3 data-number="4.1.1" id="changes-since-p2728r1"><span class="header-section-number">4.1.1</span> Changes since P2728R1<a href="#changes-since-p2728r1" class="self-link"></a></h3>
<ul>
<li>Generalize <code class="sourceCode cpp">null_sentinel_t</code> to a
non-Unicode-specific facility.</li>
</ul>
<h3 data-number="4.1.2" id="changes-since-p2728r3"><span class="header-section-number">4.1.2</span> Changes since P2728R3<a href="#changes-since-p2728r3" class="self-link"></a></h3>
<ul>
<li>Change <code class="sourceCode cpp">null_sentinel_t</code> back to
being Unicode-specific.</li>
</ul>
<h3 data-number="4.1.3" id="changes-since-p2728r4"><span class="header-section-number">4.1.3</span> Changes since P2728R4<a href="#changes-since-p2728r4" class="self-link"></a></h3>
<ul>
<li>Move <code class="sourceCode cpp">null_sentinel_t</code> to
<code class="sourceCode cpp">std</code>, remove its
<code class="sourceCode cpp">base</code> member function, and make it
useful for more than just pointers, based on SG-9 guidance.</li>
</ul>
<h3 data-number="4.1.4" id="changes-since-p2728r5"><span class="header-section-number">4.1.4</span> Changes since P2728R5<a href="#changes-since-p2728r5" class="self-link"></a></h3>
<ul>
<li>Simplify the complicated constraint on the comparison operator for
<code class="sourceCode cpp">null_sentinel_t</code>.</li>
</ul>
<h3 data-number="4.1.5" id="changes-since-p2728r6"><span class="header-section-number">4.1.5</span> Changes since P2728R6<a href="#changes-since-p2728r6" class="self-link"></a></h3>
<ul>
<li>Fix a bug in <code class="sourceCode cpp">null_sentinel_t</code>
causing it not to satisfy
<code class="sourceCode cpp">sentinel_for</code> by changing its <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">==</span></code>
to return
<code class="sourceCode cpp"><span class="dt">bool</span></code>.</li>
<li>Fix a bug in <code class="sourceCode cpp">null_sentinel_t</code>
where it did not support non-copyable input iterators by having <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">==</span></code>
take input iterators by reference.</li>
</ul>
<h3 data-number="4.1.6" id="changes-since-p2728r7"><span class="header-section-number">4.1.6</span> Changes since P2728R7<a href="#changes-since-p2728r7" class="self-link"></a></h3>
<ul>
<li>Move <code class="sourceCode cpp">null_sentinel</code> and
<code class="sourceCode cpp">null_term</code> into P3705</li>
</ul>
<h3 data-number="4.1.7" id="changes-since-p3705r0"><span class="header-section-number">4.1.7</span> Changes since P3705R0<a href="#changes-since-p3705r0" class="self-link"></a></h3>
<ul>
<li>Fix off-by-one in textual description in motivation section</li>
<li>Add example with argv and environ</li>
<li>Add <code class="sourceCode cpp">unchecked_take_before</code> design
alternative</li>
</ul>
<h3 data-number="4.1.8" id="changes-since-p3705r1"><span class="header-section-number">4.1.8</span> Changes since P3705R1<a href="#changes-since-p3705r1" class="self-link"></a></h3>
<ul>
<li>Remove <code class="sourceCode cpp">unchecked_take_before</code> and
pass-by-value design alternatives</li>
<li>Add polls and minutes from Sofia 2025 SG9 review</li>
<li>Move <code class="sourceCode cpp">null_term</code> to namespace
<code class="sourceCode cpp">std<span class="op">::</span>views</code></li>
<li>Add feature test macro</li>
<li>Add naming discussion</li>
<li>Use <code class="sourceCode cpp">iter_value_t<span class="op">&lt;</span>I<span class="op">&gt;()</span></code>
over <code class="sourceCode cpp">iter_value_t<span class="op">&lt;</span>I<span class="op">&gt;{}</span></code>
to avoid <code class="sourceCode cpp">initializer_list</code>
interaction</li>
</ul>
<h2 data-number="4.2" id="relevant-pollsminutes"><span class="header-section-number">4.2</span> Relevant Polls/Minutes<a href="#relevant-pollsminutes" class="self-link"></a></h2>
<h3 data-number="4.2.1" id="sg9-review-of-p3705r1-on-2025-06-18-during-sofia-2025"><span class="header-section-number">4.2.1</span> SG9 review of P3705R1 on
2025-06-18 during Sofia 2025<a href="#sg9-review-of-p3705r1-on-2025-06-18-during-sofia-2025" class="self-link"></a></h3>
<ul>
<li><a href="https://wiki.edg.com/bin/view/Wg21sofia2025/NotesSG9P3705R0">Minutes</a></li>
</ul>
<p><strong>POLL:</strong> We would like something like the proposed
<code class="sourceCode cpp">null_sentinel</code> regardless of the
addition of a hypothetical
<code class="sourceCode cpp">unchecked_take_before</code> view that may
come in the future.</p>
<p><strong>Outcome:</strong> No objection to unanimous consent</p>
<p><strong>POLL:</strong> Always pass the iterator by reference to <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">==</span></code>,
move <code class="sourceCode cpp">null_term</code> to namespace
<code class="sourceCode cpp">std<span class="op">::</span>views</code>,
add a discussion about alternative names, and forward P3705R1 with those
changes to LEWG for inclusion in C++29.</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>9</td>
<td>7</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p><strong># Of Authors:</strong> 1</p>
<p><strong>Author’s Position:</strong> SF</p>
<p><strong>Attendance:</strong> 18 (2 abstentions)</p>
<p><strong>Outcome:</strong> Unanimous consent</p>
<h3 data-number="4.2.2" id="sg9-review-of-d2728r4-on-2023-06-12-during-varna-2023"><span class="header-section-number">4.2.2</span> SG9 review of D2728R4 on
2023-06-12 during Varna 2023<a href="#sg9-review-of-d2728r4-on-2023-06-12-during-varna-2023" class="self-link"></a></h3>
<ul>
<li><a href="https://wiki.edg.com/bin/view/Wg21varna/P2728#SG9-2023-06-12">Minutes</a></li>
</ul>
<p><strong>POLL:</strong> Move null_sentinel_t to std:: namespace</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1</td>
<td>3</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p><strong># Of Authors:</strong> 1</p>
<p><strong>Author’s Position:</strong> F</p>
<p><strong>Attendance:</strong> 9 (4 abstentions)</p>
<p><strong>Outcome:</strong> Consensus in favor</p>
<p><br /></p>
<p><strong>POLL:</strong> Remove null_sentinel_t::base member function
from the proposal</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>0</td>
<td>4</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p><strong># Of Authors:</strong> 1</p>
<p><strong>Author’s Position:</strong> F</p>
<p><strong>Attendance:</strong> 8 (3 abstentions)</p>
<p><strong>Outcome:</strong> Consensus in favor</p>
<h3 data-number="4.2.3" id="sg16-review-of-p2728r3-on-2023-05-10-telecon"><span class="header-section-number">4.2.3</span> SG16 review of P2728R3 on
2023-05-10 (Telecon)<a href="#sg16-review-of-p2728r3-on-2023-05-10-telecon" class="self-link"></a></h3>
<ul>
<li><a href="https://github.com/sg16-unicode/sg16-meetings/blob/master/README-2023.md#may-10th-2023">Minutes</a></li>
</ul>
<p><strong>POLL:</strong> Separate <code class="sourceCode cpp">std<span class="op">::</span>null_sentinel_t</code>
from P2728 into a separate paper for SG9 and LEWG; SG16 does not need to
see it again.</p>
<table style="width:31%;">
<colgroup>
<col style="width: 6%" />
<col style="width: 5%" />
<col style="width: 5%" />
<col style="width: 5%" />
<col style="width: 6%" />
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1</td>
<td>1</td>
<td>4</td>
<td>2</td>
<td>1</td>
</tr>
</tbody>
</table>
<p><strong>Attendance:</strong> 12 (3 abstentions)</p>
<p><strong>Outcome:</strong> No consensus; author’s discretion for how
to continue.</p>
<h1 data-number="5" id="bibliography"><span class="header-section-number">5</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-P2210R2" class="csl-entry" role="doc-biblioentry">
[P2210R2] Barry Revzin. 2021-03-05. Superior String Splitting. <a href="https://wg21.link/p2210r2"><div class="csl-block">https://wg21.link/p2210r2</div></a>
</div>
<div id="ref-P2728R0" class="csl-entry" role="doc-biblioentry">
[P2728R0] Zach Laine. 2022-12-24. Unicode in the Library, Part 1: UTF
Transcoding. <a href="https://wg21.link/p2728r0"><div class="csl-block">https://wg21.link/p2728r0</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
