<!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="2021-12-17" />
  <title>Formatting Ranges</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.hanging-indent{margin-left: 1.5em; text-indent: -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; }
      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;
}
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>
  <style type="text/css">a {
color : #4183C4;
text-decoration: underline;
}
a.marginalized {
text-decoration: none;
}
a.self-link {
text-decoration: none;
}
h1#toctitle {
border-bottom: 1px solid #cccccc;
}
#TOC li {
margin-top: 1px;
margin-bottom: 1px;
}
#TOC ul>li:before { display: none; }
h3.subtitle { margin-top: -15px; }
h1:target { background-color: transparent; }
h2:target { background-color: transparent; }
h3:target { background-color: transparent; }
h4:target { background-color: transparent; }
h5:target { background-color: transparent; }
h6:target { background-color: transparent; }
code span.co { font-family: monospace; }
table tr {
background-color: white;
}
table tr:nth-child(2n) {
background-color: #f6f8fa;
}
#title-block-header > table tr:nth-child(2n) {
background-color: white;
}
td > div.sourceCode {
background-color: inherit;
}
table {
border-collapse: collapse;
}
table td, table th {
border: 1px solid #cccccc;
}
table th {
border-bottom: 1px solid black;
text-align: center;
}
table tr:first-child th {
border-top: 0;
}
table tr:last-child td {
border-bottom: 0;
}
table tr td:first-child,
table tr th:first-child {
border-left: 0;
}
table tr td:last-child,
table tr th:last-child {
border-right: 0;
}
table tbody tr:first-child td {
border-top: 1px solid black;
}
#title-block-header td { border: 0; }
@media all {
body {
margin: 2em;
}
}
@media screen and (min-width: 480px) {
body {
margin: 5em;
}
}
#refs code{padding-left: 0px; text-indent: 0px;}
:root {
--diff-ins: #e6ffed;
--diff-strongins: #acf2bd;
--diff-del: #ffdddd;
--diff-strongdel: #ff8888;
}
span.diffins {
background-color: var(--diff-strongins);
}
span.diffdel {
background-color: var(--diff-strongdel);
}
div.rm { text-decoration: line-through; }
div.rm code.sourceCode { text-decoration: line-through; }
div.addu, span.addu {
color: #006e28;
background-color: var(--diff-ins);
}

div.rm pre, div.add pre { background-color: #f6f8fa; }
div.addu pre { background-color: var(--diff-ins); }
div.add, div.add pre { background-color: var(--diff-ins); }
div.addu blockquote {
border-left: 4px solid #00a000;
padding: 0 15px;
color: #006e28;
text-decoration: none;
}
div.addu blockquote code.sourceCode { text-decoration: none; }
div.addu blockquote pre { text-decoration: none; }
div.addu blockquote pre code { text-decoration: none; }
div.quote {
border-left: 7px solid #ccc;
background: #f9f9f9;
margin: 1.5em 10px;
padding-left: 20px;
}
code.diff span.va { color: #000000; background-color: var(--diff-ins); }
code.diff span.st { color: #000000; background-color: var(--diff-del); }
</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">Formatting Ranges</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2286R4</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2021-12-17</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>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@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="#revision-history"><span class="toc-section-number">1</span> Revision History<span></span></a></li>
<li><a href="#introduction"><span class="toc-section-number">2</span> Introduction<span></span></a>
<ul>
<li><a href="#implementation-experience"><span class="toc-section-number">2.1</span> Implementation Experience<span></span></a></li>
</ul></li>
<li><a href="#proposal-considerations"><span class="toc-section-number">3</span> Proposal Considerations<span></span></a>
<ul>
<li><a href="#what-types-to-print"><span class="toc-section-number">3.1</span> What types to print?<span></span></a></li>
<li><a href="#detecting-whether-a-type-is-formattable"><span class="toc-section-number">3.2</span> Detecting whether a type is formattable<span></span></a></li>
<li><a href="#what-representation"><span class="toc-section-number">3.3</span> What representation?<span></span></a>
<ul>
<li><a href="#vector-and-other-ranges"><span class="toc-section-number">3.3.1</span> <code class="sourceCode cpp">vector</code> (and other ranges)<span></span></a></li>
<li><a href="#pair-and-tuple"><span class="toc-section-number">3.3.2</span> <code class="sourceCode cpp">pair</code> and <code class="sourceCode cpp">tuple</code><span></span></a></li>
<li><a href="#map-and-set-and-other-associative-containers"><span class="toc-section-number">3.3.3</span> <code class="sourceCode cpp">map</code> and <code class="sourceCode cpp">set</code> (and other associative containers)<span></span></a></li>
<li><a href="#char-and-string-and-other-string-like-types-in-ranges-or-tuples"><span class="toc-section-number">3.3.4</span> <code class="sourceCode cpp"><span class="dt">char</span></code> and <code class="sourceCode cpp">string</code> (and other string-like types) in ranges or tuples<span></span></a></li>
<li><a href="#filesystempath"><span class="toc-section-number">3.3.5</span> <code class="sourceCode cpp">filesystem<span class="op">::</span>path</code><span></span></a></li>
<li><a href="#format-specifiers"><span class="toc-section-number">3.3.6</span> Format Specifiers<span></span></a></li>
<li><a href="#explanation-of-added-specifiers"><span class="toc-section-number">3.3.7</span> Explanation of Added Specifiers<span></span></a>
<ul>
<li><a href="#the-debug-specifier"><span class="toc-section-number">3.3.7.1</span> The debug specifier <code class="sourceCode cpp"><span class="op">?</span></code><span></span></a></li>
<li><a href="#range-specifiers"><span class="toc-section-number">3.3.7.2</span> Range specifiers<span></span></a></li>
<li><a href="#dynamic-delimiter-for-ranges"><span class="toc-section-number">3.3.7.3</span> Dynamic Delimiter for Ranges<span></span></a></li>
<li><a href="#static-delimiter-for-ranges"><span class="toc-section-number">3.3.7.4</span> Static Delimiter for Ranges<span></span></a></li>
<li><a href="#pair-and-tuple-specifiers"><span class="toc-section-number">3.3.7.5</span> Pair and Tuple Specifiers<span></span></a></li>
</ul></li>
<li><a href="#escaping-behavior"><span class="toc-section-number">3.3.8</span> Escaping Behavior<span></span></a></li>
<li><a href="#examples-with-user-defined-types"><span class="toc-section-number">3.3.9</span> Examples with user-defined types<span></span></a></li>
</ul></li>
<li><a href="#implementation-challenges"><span class="toc-section-number">3.4</span> Implementation Challenges<span></span></a>
<ul>
<li><a href="#wrapping-basic_format_context-is-not-generally-possible"><span class="toc-section-number">3.4.1</span> Wrapping <code class="sourceCode cpp">basic_format_context</code> is not generally possible<span></span></a></li>
<li><a href="#manipulating-basic_format_parse_context-to-search-for-sentinels"><span class="toc-section-number">3.4.2</span> Manipulating <code class="sourceCode cpp">basic_format_parse_context</code> to search for sentinels<span></span></a></li>
<li><a href="#parsing-of-alignment-padding-and-width"><span class="toc-section-number">3.4.3</span> Parsing of alignment, padding, and width<span></span></a></li>
</ul></li>
<li><a href="#how-to-support-those-views-which-are-not-const-iterable"><span class="toc-section-number">3.5</span> How to support those views which are not <code class="sourceCode cpp"><span class="kw">const</span></code>-iterable?<span></span></a></li>
<li><a href="#what-additional-functionality"><span class="toc-section-number">3.6</span> What additional functionality?<span></span></a>
<ul>
<li><a href="#fmtjoin"><span class="toc-section-number">3.6.1</span> <code class="sourceCode cpp">fmt<span class="op">::</span>join</code><span></span></a></li>
</ul></li>
<li><a href="#format-or-stdcout"><span class="toc-section-number">3.7</span> <code class="sourceCode cpp">format</code> or <code class="sourceCode cpp">std<span class="op">::</span>cout</code>?<span></span></a></li>
<li><a href="#what-about-vectorbool"><span class="toc-section-number">3.8</span> What about <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span></code>?<span></span></a></li>
</ul></li>
<li><a href="#proposal"><span class="toc-section-number">4</span> Proposal<span></span></a>
<ul>
<li><a href="#wording"><span class="toc-section-number">4.1</span> Wording<span></span></a>
<ul>
<li><a href="#concept-formattable"><span class="toc-section-number">4.1.1</span> Concept <code class="sourceCode cpp">formattable</code><span></span></a></li>
<li><a href="#retargeting-format_context"><span class="toc-section-number">4.1.2</span> Retargeting <code class="sourceCode cpp">format_context</code><span></span></a></li>
<li><a href="#an-end_sentry-for-basic_parse_format_context"><span class="toc-section-number">4.1.3</span> An <code class="sourceCode cpp">end_sentry</code> for <code class="sourceCode cpp">basic_parse_format_context</code><span></span></a></li>
<li><a href="#formatting-for-ranges"><span class="toc-section-number">4.1.4</span> Formatting for ranges<span></span></a></li>
<li><a href="#formatting-for-pair-and-tuple"><span class="toc-section-number">4.1.5</span> Formatting for <code class="sourceCode cpp">pair</code> and <code class="sourceCode cpp">tuple</code><span></span></a></li>
<li><a href="#formatter-for-vectorboolreference"><span class="toc-section-number">4.1.6</span> Formatter for <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code><span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#bibliography"><span class="toc-section-number">5</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="revision-history"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>Since <span class="citation" data-cites="P2286R3">[<a href="#ref-P2286R3" role="doc-biblioref">P2286R3</a>]</span>, several major changes:</p>
<ul>
<li>Removed the special <code class="sourceCode cpp">pair</code>/<code class="sourceCode cpp">tuple</code> parsing for individual elements. This proved complicated and illegible, and led to having to deal with more issues that would make this paper harder to make it for C++23.</li>
<li>Adding sections on <a href="#dynamic-delimiter-for-ranges">dynamic</a> and <a href="#static-delimiter-for-ranges">static</a> delimiters for ranges. Removing <code class="sourceCode cpp">std<span class="op">::</span>format_join</code> in their favor.</li>
<li>Renaming <code class="sourceCode cpp">format_as_debug</code> to <code class="sourceCode cpp">set_debug_format</code> (since it’s not actually <em>formatting</em> anything, it’s just setting up)</li>
<li>Discussing <code class="sourceCode cpp">std<span class="op">::</span>filesystem<span class="op">::</span>path</code></li>
</ul>
<p>Since <span class="citation" data-cites="P2286R2">[<a href="#ref-P2286R2" role="doc-biblioref">P2286R2</a>]</span>, several major changes:</p>
<ul>
<li>This paper assumes the adoption of <span class="citation" data-cites="P2418R0">[<a href="#ref-P2418R0" role="doc-biblioref">P2418R0</a>]</span>, which affects how <a href="#how-to-support-those-views-which-are-not-const-iterable">non-<code class="sourceCode cpp"><span class="kw">const</span></code>-iterable views</a> are handled. This paper now introduces two concepts (<code class="sourceCode cpp">formattable</code> and <code class="sourceCode cpp">const_formattable</code>) instead of just one.</li>
<li>Extended discussion and functionality for various <a href="#what-representation">representations</a>, including how to quote strings properly and how to format associative ranges.</li>
<li>Introduction of format specifiers of all kinds and discussion of how to make them work more broadly.</li>
<li>Removed the wording, since the priority is the design.</li>
</ul>
<p>Since <span class="citation" data-cites="P2286R1">[<a href="#ref-P2286R1" role="doc-biblioref">P2286R1</a>]</span>, adding a sketch of wording.</p>
<p><span class="citation" data-cites="P2286R0">[<a href="#ref-P2286R0" role="doc-biblioref">P2286R0</a>]</span> suggested making all the formatting implementation-defined. Several people reached out to me suggesting in no uncertain terms that this is unacceptable. This revision lays out options for such formatting.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">2</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p><span class="citation" data-cites="LWG3478">[<a href="#ref-LWG3478" role="doc-biblioref">LWG3478</a>]</span> addresses the issue of what happens when you split a string and the last character in the string is the delimiter that you are splitting on. One of the things I wanted to look at in research in that issue is: what do <em>other</em> languages do here?</p>
<p>For most languages, this is a pretty easy proposition. Do the split, print the results. This is usually only a few lines of code.</p>
<p>Python:</p>
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1"></a><span class="bu">print</span>(<span class="st">&quot;xyx&quot;</span>.split(<span class="st">&quot;x&quot;</span>))</span></code></pre></div>
<p>outputs</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb1-1"><a href="#cb1-1"></a>[&#39;&#39;, &#39;y&#39;, &#39;&#39;]</span></code></pre></div>
</blockquote>
<p>Java (where the obvious thing prints something useless, but there’s a non-obvious thing that is useful):</p>
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode java"><code class="sourceCode java"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">import</span><span class="im"> java.util.Arrays;</span></span>
<span id="cb2-2"><a href="#cb2-2"></a></span>
<span id="cb2-3"><a href="#cb2-3"></a><span class="kw">class</span> Main {</span>
<span id="cb2-4"><a href="#cb2-4"></a>  <span class="kw">public</span> <span class="dt">static</span> <span class="dt">void</span> <span class="fu">main</span>(<span class="bu">String</span> args[]) {</span>
<span id="cb2-5"><a href="#cb2-5"></a>    <span class="bu">System</span>.<span class="fu">out</span>.<span class="fu">println</span>(<span class="st">&quot;xyx&quot;</span>.<span class="fu">split</span>(<span class="st">&quot;x&quot;</span>));</span>
<span id="cb2-6"><a href="#cb2-6"></a>    <span class="bu">System</span>.<span class="fu">out</span>.<span class="fu">println</span>(<span class="bu">Arrays</span>.<span class="fu">toString</span>(<span class="st">&quot;xyx&quot;</span>.<span class="fu">split</span>(<span class="st">&quot;x&quot;</span>)));</span>
<span id="cb2-7"><a href="#cb2-7"></a>  }</span>
<span id="cb2-8"><a href="#cb2-8"></a>}</span></code></pre></div>
<p>outputs</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb2-1"><a href="#cb2-1"></a>[Ljava.lang.String;@76ed5528</span>
<span id="cb2-2"><a href="#cb2-2"></a>[, y]</span></code></pre></div>
</blockquote>
<p>Rust (a couple options, including also another false friend):</p>
<blockquote>
<div class="sourceCode" id="cb3"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">use</span> <span class="pp">itertools::</span>Itertools<span class="op">;</span></span>
<span id="cb3-2"><a href="#cb3-2"></a></span>
<span id="cb3-3"><a href="#cb3-3"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4"></a>    <span class="pp">println!</span>(<span class="st">&quot;{:?}&quot;</span><span class="op">,</span> <span class="st">&quot;xyx&quot;</span><span class="op">.</span>split(<span class="ch">&#39;x&#39;</span>))<span class="op">;</span></span>
<span id="cb3-5"><a href="#cb3-5"></a>    <span class="pp">println!</span>(<span class="st">&quot;[{}]&quot;</span><span class="op">,</span> <span class="st">&quot;xyx&quot;</span><span class="op">.</span>split(<span class="ch">&#39;x&#39;</span>)<span class="op">.</span>format(<span class="st">&quot;, &quot;</span>))<span class="op">;</span></span>
<span id="cb3-6"><a href="#cb3-6"></a>    <span class="pp">println!</span>(<span class="st">&quot;{:?}&quot;</span><span class="op">,</span> <span class="st">&quot;xyx&quot;</span><span class="op">.</span>split(<span class="ch">&#39;x&#39;</span>)<span class="op">.</span><span class="pp">collect::</span><span class="op">&lt;</span><span class="dt">Vec</span><span class="op">&lt;</span>_<span class="op">&gt;&gt;</span>())<span class="op">;</span></span>
<span id="cb3-7"><a href="#cb3-7"></a><span class="op">}</span></span></code></pre></div>
<p>outputs</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb3-1"><a href="#cb3-1"></a>Split(SplitInternal { start: 0, end: 3, matcher: CharSearcher { haystack: &quot;xyx&quot;, finger: 0, finger_back: 3, needle: &#39;x&#39;, utf8_size: 1, utf8_encoded: [120, 0, 0, 0] }, allow_trailing_empty: true, finished: false })</span>
<span id="cb3-2"><a href="#cb3-2"></a>[, y, ]</span>
<span id="cb3-3"><a href="#cb3-3"></a>[&quot;&quot;, &quot;y&quot;, &quot;&quot;]</span></code></pre></div>
</blockquote>
<p>Kotlin:</p>
<blockquote>
<div class="sourceCode" id="cb4"><pre class="sourceCode kotlin"><code class="sourceCode kotlin"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">fun</span> <span class="fu">main</span>() {</span>
<span id="cb4-2"><a href="#cb4-2"></a>    println(<span class="st">&quot;xyx&quot;</span>.split(<span class="st">&quot;x&quot;</span>));</span>
<span id="cb4-3"><a href="#cb4-3"></a>}</span></code></pre></div>
<p>outputs</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb4-1"><a href="#cb4-1"></a>[, y, ]</span></code></pre></div>
</blockquote>
<p>Go:</p>
<blockquote>
<div class="sourceCode" id="cb5"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">package</span> main</span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="kw">import</span> <span class="st">&quot;fmt&quot;</span></span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="kw">import</span> <span class="st">&quot;strings&quot;</span></span>
<span id="cb5-4"><a href="#cb5-4"></a></span>
<span id="cb5-5"><a href="#cb5-5"></a><span class="kw">func</span> main() {</span>
<span id="cb5-6"><a href="#cb5-6"></a>    fmt.Println(strings.Split(<span class="st">&quot;xyx&quot;</span>, <span class="st">&quot;x&quot;</span>));</span>
<span id="cb5-7"><a href="#cb5-7"></a>}</span></code></pre></div>
<p>outputs</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb5-1"><a href="#cb5-1"></a>[ y ]</span></code></pre></div>
</blockquote>
<p>JavaScript:</p>
<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb6-1"><a href="#cb6-1"></a><span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(<span class="st">&#39;xyx&#39;</span><span class="op">.</span><span class="fu">split</span>(<span class="st">&#39;x&#39;</span>))</span></code></pre></div>
<p>outputs</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb6-1"><a href="#cb6-1"></a>[ &#39;&#39;, &#39;y&#39;, &#39;&#39; ]</span></code></pre></div>
</blockquote>
<p>And so on and so forth. What we see across these languages is that printing the result of split is pretty easy. In most cases, whatever the print mechanism is just works and does something meaningful. In other cases, printing gave me something other than what I wanted but some other easy, provided mechanism for doing so.</p>
<p>Now let’s consider C++.</p>
<blockquote>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="pp">#include </span><span class="im">&lt;string&gt;</span></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="pp">#include </span><span class="im">&lt;ranges&gt;</span></span>
<span id="cb7-4"><a href="#cb7-4"></a><span class="pp">#include </span><span class="im">&lt;format&gt;</span></span>
<span id="cb7-5"><a href="#cb7-5"></a></span>
<span id="cb7-6"><a href="#cb7-6"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb7-7"><a href="#cb7-7"></a>    <span class="co">// need to predeclare this because we can&#39;t split an rvalue string</span></span>
<span id="cb7-8"><a href="#cb7-8"></a>    std<span class="op">::</span>string s <span class="op">=</span> <span class="st">&quot;xyx&quot;</span>;</span>
<span id="cb7-9"><a href="#cb7-9"></a>    <span class="kw">auto</span> parts <span class="op">=</span> s <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>split<span class="op">(</span><span class="ch">&#39;x&#39;</span><span class="op">)</span>;</span>
<span id="cb7-10"><a href="#cb7-10"></a></span>
<span id="cb7-11"><a href="#cb7-11"></a>    <span class="co">// nope</span></span>
<span id="cb7-12"><a href="#cb7-12"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> parts;</span>
<span id="cb7-13"><a href="#cb7-13"></a></span>
<span id="cb7-14"><a href="#cb7-14"></a>    <span class="co">// nope (assuming std::print from P2093)</span></span>
<span id="cb7-15"><a href="#cb7-15"></a>    std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}&quot;</span>, parts<span class="op">)</span>;</span>
<span id="cb7-16"><a href="#cb7-16"></a></span>
<span id="cb7-17"><a href="#cb7-17"></a></span>
<span id="cb7-18"><a href="#cb7-18"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;[&quot;</span>;</span>
<span id="cb7-19"><a href="#cb7-19"></a>    <span class="dt">char</span> <span class="kw">const</span><span class="op">*</span> delim <span class="op">=</span> <span class="st">&quot;&quot;</span>;</span>
<span id="cb7-20"><a href="#cb7-20"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> part <span class="op">:</span> parts<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-21"><a href="#cb7-21"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> delim;</span>
<span id="cb7-22"><a href="#cb7-22"></a></span>
<span id="cb7-23"><a href="#cb7-23"></a>        <span class="co">// still nope</span></span>
<span id="cb7-24"><a href="#cb7-24"></a>        std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> part;</span>
<span id="cb7-25"><a href="#cb7-25"></a></span>
<span id="cb7-26"><a href="#cb7-26"></a>        <span class="co">// also nope</span></span>
<span id="cb7-27"><a href="#cb7-27"></a>        std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}&quot;</span>, part<span class="op">)</span>;</span>
<span id="cb7-28"><a href="#cb7-28"></a></span>
<span id="cb7-29"><a href="#cb7-29"></a>        <span class="co">// this finally works</span></span>
<span id="cb7-30"><a href="#cb7-30"></a>        std<span class="op">::</span>ranges<span class="op">::</span>copy<span class="op">(</span>part, std<span class="op">::</span>ostream_iterator<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;(</span>std<span class="op">::</span>cout<span class="op">))</span>;</span>
<span id="cb7-31"><a href="#cb7-31"></a></span>
<span id="cb7-32"><a href="#cb7-32"></a>        <span class="co">// as does this</span></span>
<span id="cb7-33"><a href="#cb7-33"></a>        <span class="cf">for</span> <span class="op">(</span><span class="dt">char</span> c <span class="op">:</span> part<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-34"><a href="#cb7-34"></a>            std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> c;</span>
<span id="cb7-35"><a href="#cb7-35"></a>        <span class="op">}</span></span>
<span id="cb7-36"><a href="#cb7-36"></a>        delim <span class="op">=</span> <span class="st">&quot;, &quot;</span>;</span>
<span id="cb7-37"><a href="#cb7-37"></a>    <span class="op">}</span></span>
<span id="cb7-38"><a href="#cb7-38"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> <span class="st">&quot;]</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb7-39"><a href="#cb7-39"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This took me more time to write than any of the solutions in any of the other languages. Including the Go solution, which contains 100% of all the lines of Go I’ve written in my life.</p>
<p>Printing is a fairly fundamental and universal mechanism to see what’s going on in your program. In the context of ranges, it’s probably the most useful way to see and understand what the various range adapters actually do. But none of these things provides an <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;&lt;</span></code> (for <code class="sourceCode cpp">std<span class="op">::</span>cout</code>) or a formatter specialization (for <code class="sourceCode cpp">format</code>). And the further problem is that as a user, I can’t even do anything about this. I can’t just provide an <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;&lt;</span></code> in <code class="sourceCode cpp"><span class="kw">namespace</span> std</code> or a very broad specialization of <code class="sourceCode cpp">formatter</code> - none of these are program-defined types, so it’s just asking for clashes once you start dealing with bigger programs.</p>
<p>The only mechanisms I have at my disposal to print something like this is either</p>
<ol type="1">
<li>nested loops with hand-written delimiter handling (which are tedious and a bad solution), or</li>
<li>at least replace the inner-most loop with a <code class="sourceCode cpp">ranges<span class="op">::</span>copy</code> into an output iterator (which is more differently bad), or</li>
<li>Write my own formatting library that I <em>am</em> allowed to specialize (which is not only bad but also ridiculous)</li>
<li>Use <code class="sourceCode cpp">fmt<span class="op">::</span>format</code>.</li>
</ol>
<h2 data-number="2.1" id="implementation-experience"><span class="header-section-number">2.1</span> Implementation Experience<a href="#implementation-experience" class="self-link"></a></h2>
<p>That’s right, there’s a fourth option for C++ that I haven’t shown yet, and that’s this:</p>
<blockquote>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="pp">#include </span><span class="im">&lt;ranges&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2"></a><span class="pp">#include </span><span class="im">&lt;string&gt;</span></span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="pp">#include </span><span class="im">&lt;fmt/ranges.h&gt;</span></span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-6"><a href="#cb8-6"></a>    std<span class="op">::</span>string s <span class="op">=</span> <span class="st">&quot;xyx&quot;</span>;</span>
<span id="cb8-7"><a href="#cb8-7"></a>    <span class="kw">auto</span> parts <span class="op">=</span> s <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>split<span class="op">(</span><span class="ch">&#39;x&#39;</span><span class="op">)</span>;</span>
<span id="cb8-8"><a href="#cb8-8"></a></span>
<span id="cb8-9"><a href="#cb8-9"></a>    fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}</span><span class="sc">\n</span><span class="st">&quot;</span>, parts<span class="op">)</span>;</span>
<span id="cb8-10"><a href="#cb8-10"></a>    fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;&lt;&lt;{}&gt;&gt;</span><span class="sc">\n</span><span class="st">&quot;</span>, fmt<span class="op">::</span>join<span class="op">(</span>parts, <span class="st">&quot;--&quot;</span><span class="op">))</span>;</span>
<span id="cb8-11"><a href="#cb8-11"></a><span class="op">}</span></span></code></pre></div>
<p>outputting</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb9-1"><a href="#cb9-1"></a>[[], [&#39;y&#39;], []]</span>
<span id="cb9-2"><a href="#cb9-2"></a>&lt;&lt;[]--[&#39;y&#39;]--[]&gt;&gt;</span></code></pre></div>
</blockquote>
<p>And this is great! It’s a single, easy line of code to just print arbitrary ranges (include ranges of ranges).</p>
<p>And, if I want to do something more involved, there’s also <code class="sourceCode cpp">fmt<span class="op">::</span>join</code>, which lets me specify both a format specifier and a delimiter. For instance:</p>
<blockquote>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">uint8_t</span><span class="op">&gt;</span> mac <span class="op">=</span> <span class="op">{</span><span class="bn">0xaa</span>, <span class="bn">0xbb</span>, <span class="bn">0xcc</span>, <span class="bn">0xdd</span>, <span class="bn">0xee</span>, <span class="bn">0xff</span><span class="op">}</span>;</span>
<span id="cb10-2"><a href="#cb10-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, fmt<span class="op">::</span>join<span class="op">(</span>mac, <span class="st">&quot;:&quot;</span><span class="op">))</span>;</span></code></pre></div>
<p>outputs</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb11-1"><a href="#cb11-1"></a>aa:bb:cc:dd:ee:ff</span></code></pre></div>
</blockquote>
<p><code class="sourceCode cpp">fmt<span class="op">::</span>format</code> (and <code class="sourceCode cpp">fmt<span class="op">::</span>print</code>) solves my problem completely. <code class="sourceCode cpp">std<span class="op">::</span>format</code> does not, and it should.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="proposal-considerations"><span class="header-section-number">3</span> Proposal Considerations<a href="#proposal-considerations" class="self-link"></a></h1>
<p>The Ranges Plan for C++23 <span class="citation" data-cites="P2214R1">[<a href="#ref-P2214R1" role="doc-biblioref">P2214R1</a>]</span> listed as one of its top priorities for C++23 as the ability to format all views. Let’s go through the issues we need to address in order to get this functionality.</p>
<h2 data-number="3.1" id="what-types-to-print"><span class="header-section-number">3.1</span> What types to print?<a href="#what-types-to-print" class="self-link"></a></h2>
<p>The standard library is the only library that can provide formatting support for standard library types and other broad classes of types like ranges. In addition to ranges (both the conrete containers like <code class="sourceCode cpp">vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code> and the range adaptors like <code class="sourceCode cpp">views<span class="op">::</span>split</code>), there are several very commonly used types that are currently not printable.</p>
<p>The most common and important such types are <code class="sourceCode cpp">pair</code> and <code class="sourceCode cpp">tuple</code> (which ties back into Ranges even more closely once we adopt <code class="sourceCode cpp">views<span class="op">::</span>zip</code> and <code class="sourceCode cpp">views<span class="op">::</span>enumerate</code>). <code class="sourceCode cpp">fmt</code> currently supports printing such types as well:</p>
<blockquote>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}</span><span class="sc">\n</span><span class="st">&quot;</span>, std<span class="op">::</span>pair<span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">))</span>;</span></code></pre></div>
<p>outputs</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb13-1"><a href="#cb13-1"></a>(1, 2)</span></code></pre></div>
</blockquote>
<p>Another common and important set of types are <code class="sourceCode cpp">std<span class="op">::</span>optional<span class="op">&lt;</span>T<span class="op">&gt;</span></code> and <code class="sourceCode cpp">std<span class="op">::</span>variant<span class="op">&lt;</span>Ts<span class="op">...&gt;</span></code>. <code class="sourceCode cpp">fmt</code> does not support printing any of the sum types. There is not an obvious representation for them in C++ as there might be in other languages (e.g. in Rust, an <code class="sourceCode cpp">Option<span class="op">&lt;</span>i32<span class="op">&gt;</span></code> prints as either <code class="sourceCode cpp">Some<span class="op">(</span><span class="dv">42</span><span class="op">)</span></code> or <code class="sourceCode cpp">None</code>, which is also the same syntax used to construct them).</p>
<p>However, the point here isn’t necessarily to produce the best possible representation (users who have very specific formatting needs will need to write custom code anyway), but rather to provide something useful. And it’d be useful to print these types as well. However, given that <code class="sourceCode cpp">optional</code> and <code class="sourceCode cpp">variant</code> are both less closely related to Ranges than <code class="sourceCode cpp">pair</code> and <code class="sourceCode cpp">tuple</code> and also have less obvious representation, they are less important.</p>
<h2 data-number="3.2" id="detecting-whether-a-type-is-formattable"><span class="header-section-number">3.2</span> Detecting whether a type is formattable<a href="#detecting-whether-a-type-is-formattable" class="self-link"></a></h2>
<p>We need to be able to conditionally provide formatters for generic types. <code class="sourceCode cpp">vector<span class="op">&lt;</span>T<span class="op">&gt;</span></code> needs to be formattable when <code class="sourceCode cpp">T</code> is formattable. <code class="sourceCode cpp">pair<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code> needs to be formattable when <code class="sourceCode cpp">T</code> and <code class="sourceCode cpp">U</code> are formattable. In order to do this, we need to provide a proper <code class="sourceCode cpp"><span class="kw">concept</span></code> version of the formatter requirements that we already have.</p>
<p>This paper suggests the following:</p>
<blockquote>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span> charT<span class="op">&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2"></a><span class="kw">concept</span> <em>formattable-impl</em> <span class="op">=</span></span>
<span id="cb14-3"><a href="#cb14-3"></a>    semiregular<span class="op">&lt;</span>formatter<span class="op">&lt;</span>T, charT<span class="op">&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb14-4"><a href="#cb14-4"></a>    <span class="kw">requires</span> <span class="op">(</span>formatter<span class="op">&lt;</span>T, charT<span class="op">&gt;</span> f,</span>
<span id="cb14-5"><a href="#cb14-5"></a>              <span class="kw">const</span> formatter<span class="op">&lt;</span>T, charT<span class="op">&gt;</span> cf,</span>
<span id="cb14-6"><a href="#cb14-6"></a>              T t,</span>
<span id="cb14-7"><a href="#cb14-7"></a>              basic_format_context<span class="op">&lt;</span><em>fmt-iter-for</em><span class="op">&lt;</span>charT<span class="op">&gt;</span>, charT<span class="op">&gt;</span> fc,</span>
<span id="cb14-8"><a href="#cb14-8"></a>              basic_format_parse_context<span class="op">&lt;</span>charT<span class="op">&gt;</span> pc<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-9"><a href="#cb14-9"></a>        <span class="op">{</span> f<span class="op">.</span>parse<span class="op">(</span>pc<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span>basic_format_parse_context<span class="op">&lt;</span>charT<span class="op">&gt;::</span>iterator<span class="op">&gt;</span>;</span>
<span id="cb14-10"><a href="#cb14-10"></a>        <span class="op">{</span> cf<span class="op">.</span>format<span class="op">(</span>t, fc<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> same_as<span class="op">&lt;</span><em>fmt-iter-for</em><span class="op">&lt;</span>charT<span class="op">&gt;&gt;</span>;</span>
<span id="cb14-11"><a href="#cb14-11"></a>    <span class="op">}</span>;</span>
<span id="cb14-12"><a href="#cb14-12"></a></span>
<span id="cb14-13"><a href="#cb14-13"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span> charT<span class="op">&gt;</span></span>
<span id="cb14-14"><a href="#cb14-14"></a><span class="kw">concept</span> formattable <span class="op">=</span> <em>formattable-impl</em><span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>T<span class="op">&gt;</span>, charT<span class="op">&gt;</span>;</span></code></pre></div>
</blockquote>
<p>The broad shape of this concept is just taking the Formatter requirements and turning them into code. There are a few important things to note though:</p>
<ul>
<li>We don’t specify what the iterator type is of <code class="sourceCode cpp">format_context</code> or <code class="sourceCode cpp">wformat_context</code>, the expectation is that formatters accept any iterator. As such, it is unspecified in the concept <em>which</em> iterator will be checked - simply that it is <em>some</em> <code class="sourceCode cpp">output_iterator<span class="op">&lt;</span>charT <span class="kw">const</span><span class="op">&amp;&gt;</span></code>. Implementations could use <code class="sourceCode cpp">format_context<span class="op">::</span>iterator</code> and <code class="sourceCode cpp">wformat_context<span class="op">::</span>iterator</code>, or they could have a bespoke minimal iterator dedicated for concept checking.</li>
<li><code class="sourceCode cpp">cf<span class="op">.</span>format<span class="op">(</span>t, fc<span class="op">)</span></code> is called on a <code class="sourceCode cpp"><span class="kw">const</span></code> <code class="sourceCode cpp">formatter</code> (see <span class="citation" data-cites="LWG3636">[<a href="#ref-LWG3636" role="doc-biblioref">LWG3636</a>]</span>)</li>
<li><code class="sourceCode cpp">cf<span class="op">.</span>format<span class="op">(</span>t, fc<span class="op">)</span></code> is called specifically on <code class="sourceCode cpp">T</code>, not a <code class="sourceCode cpp"><span class="kw">const</span> T</code>. Even if the typical formatter specialization will take its object as <code class="sourceCode cpp"><span class="kw">const</span> T<span class="op">&amp;</span></code>. This is to handle cases like ranges that are not <code class="sourceCode cpp"><span class="kw">const</span></code>-iterable.</li>
<li><code class="sourceCode cpp">formattable<span class="op">&lt;</span>T <span class="kw">const</span>, <span class="dt">char</span><span class="op">&gt;</span></code> could be <code class="sourceCode cpp"><span class="kw">true</span></code> even if you can’t actually format a <code class="sourceCode cpp">T <span class="kw">const</span></code>. I’m not sure that this will be a significant issue in practice.</li>
</ul>
<h2 data-number="3.3" id="what-representation"><span class="header-section-number">3.3</span> What representation?<a href="#what-representation" class="self-link"></a></h2>
<p>There are several questions to ask about what the representation should be for printing. I’ll go through each kind in turn.</p>
<h3 data-number="3.3.1" id="vector-and-other-ranges"><span class="header-section-number">3.3.1</span> <code class="sourceCode cpp">vector</code> (and other ranges)<a href="#vector-and-other-ranges" class="self-link"></a></h3>
<p>Should <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code> be printed as <code class="sourceCode cpp"><span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code> or <code class="sourceCode cpp"><span class="op">[</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">]</span></code>? At the time of <span class="citation" data-cites="P2286R1">[<a href="#ref-P2286R1" role="doc-biblioref">P2286R1</a>]</span>, <code class="sourceCode cpp">fmt</code> used <code class="sourceCode cpp"><span class="op">{}</span></code>s but changed to use <code class="sourceCode cpp"><span class="op">[]</span></code>s for consistency with Python (<a href="https://github.com/fmtlib/fmt/commit/400b953fbb420ff1e47565303c64223445a51955">400b953f</a>).</p>
<p>Even though in C++ we initialize <code class="sourceCode cpp">vector</code>s (and, generally, other containers as well) with <code class="sourceCode cpp"><span class="op">{}</span></code>s while Python’s uses <code class="sourceCode cpp"><span class="op">[</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">]</span></code> (and likewise Rust has <code class="sourceCode cpp">vec<span class="op">![</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">]</span></code>), <code class="sourceCode cpp"><span class="op">[]</span></code> is typical representationally so seems like the clear best choice here.</p>
<h3 data-number="3.3.2" id="pair-and-tuple"><span class="header-section-number">3.3.2</span> <code class="sourceCode cpp">pair</code> and <code class="sourceCode cpp">tuple</code><a href="#pair-and-tuple" class="self-link"></a></h3>
<p>Should <code class="sourceCode cpp">std<span class="op">::</span>pair<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">int</span><span class="op">&gt;{</span><span class="dv">4</span>, <span class="dv">5</span><span class="op">}</span></code> be printed as <code class="sourceCode cpp"><span class="op">{</span><span class="dv">4</span>, <span class="dv">5</span><span class="op">}</span></code> or <code class="sourceCode cpp"><span class="op">(</span><span class="dv">4</span>, <span class="dv">5</span><span class="op">)</span></code>? Here, either syntax can claim to be the syntax used to initialize the <code class="sourceCode cpp">pair</code>/<code class="sourceCode cpp">tuple</code>. <code class="sourceCode cpp">fmt</code> has always printed these types with <code class="sourceCode cpp"><span class="op">()</span></code>s, and this is also how Python and Rust print such types. As with using <code class="sourceCode cpp"><span class="op">[]</span></code> for ranges, <code class="sourceCode cpp"><span class="op">()</span></code> seems like the common representation for tuples and so seems like the clear best choice.</p>
<h3 data-number="3.3.3" id="map-and-set-and-other-associative-containers"><span class="header-section-number">3.3.3</span> <code class="sourceCode cpp">map</code> and <code class="sourceCode cpp">set</code> (and other associative containers)<a href="#map-and-set-and-other-associative-containers" class="self-link"></a></h3>
<p>Should <code class="sourceCode cpp">std<span class="op">::</span>map<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">int</span><span class="op">&gt;{</span>{<span class="dv">1</span>, <span class="dv">2</span><span class="op">}</span>, <span class="op">{</span><span class="dv">3</span>, <span class="dv">4</span><span class="op">}}</span></code> be printed as <code class="sourceCode cpp"><span class="op">[(</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">)</span>, <span class="op">(</span><span class="dv">3</span>, <span class="dv">4</span><span class="op">)]</span></code> (as follows directly from the two previous choices) or as <code class="sourceCode cpp"><span class="op">{</span><span class="dv">1</span><span class="op">:</span> <span class="dv">2</span>, <span class="dv">3</span><span class="op">:</span> <span class="dv">4</span><span class="op">}</span></code> (which makes the <em>association</em> clearer in the printing)? Both Python and Rust print their associating containers this latter way.</p>
<p>The same question holds for sets as well as maps, it’s just a question for whether <code class="sourceCode cpp">std<span class="op">::</span>set<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code> prints as <code class="sourceCode cpp"><span class="op">[</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">]</span></code> (i.e. as any other range of <code class="sourceCode cpp"><span class="dt">int</span></code>) or <code class="sourceCode cpp"><span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code>?</p>
<p>If we print <code class="sourceCode cpp">map</code>s as any other range of pairs, there’s nothing left to do. If we print <code class="sourceCode cpp">map</code>s as associations, then we additionally have to answer the question of how user-defined associative containers can get printed in the same way. Hold onto this thought for a minute.</p>
<h3 data-number="3.3.4" id="char-and-string-and-other-string-like-types-in-ranges-or-tuples"><span class="header-section-number">3.3.4</span> <code class="sourceCode cpp"><span class="dt">char</span></code> and <code class="sourceCode cpp">string</code> (and other string-like types) in ranges or tuples<a href="#char-and-string-and-other-string-like-types-in-ranges-or-tuples" class="self-link"></a></h3>
<p>Should <code class="sourceCode cpp">pair<span class="op">&lt;</span><span class="dt">char</span>, string<span class="op">&gt;(</span><span class="ch">&#39;x&#39;</span>, <span class="st">&quot;hello&quot;</span><span class="op">)</span></code> print as <code class="x">(x, hello)</code> or <code class="x">(&#39;x&#39;, &quot;hello&quot;)</code>? Should <code class="sourceCode cpp">pair<span class="op">&lt;</span><span class="dt">char</span>, string<span class="op">&gt;(</span><span class="ch">&#39;y&#39;</span>, <span class="st">&quot;with</span><span class="sc">\n\&quot;</span><span class="st">quotes</span><span class="sc">\&quot;</span><span class="st">&quot;</span><span class="op">)</span></code> print as:</p>
<blockquote>
<div class="sourceCode" id="cb15"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb15-1"><a href="#cb15-1"></a>(y, with</span>
<span id="cb15-2"><a href="#cb15-2"></a>&quot;quotes&quot;)</span></code></pre></div>
</blockquote>
<p>or</p>
<blockquote>
<div class="sourceCode" id="cb16"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb16-1"><a href="#cb16-1"></a>(&#39;y&#39;, &quot;with\n\&quot;quotes\&quot;&quot;)</span></code></pre></div>
</blockquote>
<p>While <code class="sourceCode cpp"><span class="dt">char</span></code> and <code class="sourceCode cpp">string</code> are typically printed unquoted, it is quite common to print them quoted when contained in tuples and ranges. This makes it obvious what the actual elements of the range and tuple are even when the string/char contains characters like comma or space. Python, Rust, and <code class="sourceCode cpp">fmt</code> all do this. Rust escapes internal strings, so prints as <code class="sourceCode cpp"><span class="op">(</span><span class="ch">&#39;y&#39;</span>, <span class="st">&quot;with</span><span class="sc">\n\&quot;</span><span class="st">quotes</span><span class="sc">\&quot;</span><span class="st">&quot;</span><span class="op">)</span></code> (the Rust implementation of <code class="sourceCode cpp">Debug</code> for <code class="sourceCode cpp">str</code> can be found <a href="https://doc.rust-lang.org/src/core/fmt/mod.rs.html#2073-2095">here</a> which is implemented in terms of <a href="https://doc.rust-lang.org/src/core/char/methods.rs.html#405-419"><code class="sourceCode cpp">escape_debug_ext</code></a>). Following discussion of this paper and this design, Victor Zverovich implemented in this <code class="sourceCode cpp">fmt</code> as well.</p>
<p>Escaping is the most desirable default behavior, and the specific escaping behavior is described <a href="#escaping-behavior">here</a>.</p>
<p>Also, <code class="sourceCode cpp">std<span class="op">::</span>string</code> isn’t the only string-like type: if we decide to print strings quoted, how do users opt in to this behavior for their own string-like types? And <code class="sourceCode cpp"><span class="dt">char</span></code> and <code class="sourceCode cpp">string</code> aren’t the only types that may desire to have some kind of <em>debug</em> format and some kind of regular format, how to differentiate those?</p>
<p>Moreover, it’s all well and good to have the default formatting option for a range or tuple of strings to be printing those strings escaped. But what if users want to print a range of strings <em>unescaped</em>? I’ll get back to this.</p>
<h3 data-number="3.3.5" id="filesystempath"><span class="header-section-number">3.3.5</span> <code class="sourceCode cpp">filesystem<span class="op">::</span>path</code><a href="#filesystempath" class="self-link"></a></h3>
<p>We have a paper, <span class="citation" data-cites="P1636R2">[<a href="#ref-P1636R2" role="doc-biblioref">P1636R2</a>]</span>, that proposes <code class="sourceCode cpp">formatter</code> specializations for a different subset of library types: <code class="sourceCode cpp">basic_streambuf</code>, <code class="sourceCode cpp">bitset</code>, <code class="sourceCode cpp">complex</code>, <code class="sourceCode cpp">error_code</code>, <code class="sourceCode cpp">filesystem<span class="op">::</span>path</code>, <code class="sourceCode cpp">shared_ptr</code>, <code class="sourceCode cpp">sub_match</code>, <code class="sourceCode cpp">thread<span class="op">::</span>id</code>, and <code class="sourceCode cpp">unique_ptr</code>. Most of those are neither ranges nor tuples, so that paper doesn’t overlap with this one.</p>
<p>Except for one: <code class="sourceCode cpp">filesystem<span class="op">::</span>path</code>.</p>
<p>During the <a href="https://github.com/sg16-unicode/sg16-meetings#september-22nd-2021">SG16 discussion of P1636</a>, they took a poll that:</p>
<blockquote>
<p>Poll 1: Recommend removing the filesystem::path formatter from P1636 “Formatters for library types”, and specifically disabling filesystem::path formatting in P2286 “Formatting ranges”, pending a proposal with specific design for how to format paths properly.</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>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>5</td>
<td>5</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
</blockquote>
<p><code class="sourceCode cpp">filesystem<span class="op">::</span>path</code> is kind of an interesting range, since it’s a range of <code class="sourceCode cpp">path</code>. As such, checking to see if it would be formattable as this paper currently does would lead to constraint recursion:</p>
<blockquote>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1"></a><span class="kw">template</span> <span class="op">&lt;</span>range R<span class="op">&gt;</span></span>
<span id="cb17-2"><a href="#cb17-2"></a>    <span class="kw">requires</span> formattable<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></span>
<span id="cb17-3"><a href="#cb17-3"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>R<span class="op">&gt;</span></span>
<span id="cb17-4"><a href="#cb17-4"></a>    <span class="op">:</span> range_formatter<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></span>
<span id="cb17-5"><a href="#cb17-5"></a><span class="op">{</span> <span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>For <code class="sourceCode cpp">R<span class="op">=</span>filesystem<span class="op">::</span>path</code>, <code class="sourceCode cpp">range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;</span></code> is also <code class="sourceCode cpp">filesystem<span class="op">::</span>path</code>. Which means that our constraint for <code class="sourceCode cpp">formatter<span class="op">&lt;</span>fs<span class="op">::</span>path<span class="op">&gt;</span></code> requires <code class="sourceCode cpp">formattable<span class="op">&lt;</span>fs<span class="op">::</span>path<span class="op">&gt;</span></code> Looking at the <a href="#detecting-whether-a-type-is-formattable">suggested concept</a>, the first check we will do is to verify that <code class="sourceCode cpp">formatter<span class="op">&lt;</span>fs<span class="op">::</span>path<span class="op">&gt;</span></code> is <code class="sourceCode cpp">semiregular</code>. But we’re currently in the process of instantiating <code class="sourceCode cpp">formatter<span class="op">&lt;</span>fs<span class="op">::</span>path<span class="op">&gt;</span></code>, it is still incomplete. Hard error.</p>
<p>In order to handle this case properly, we could do what SG16 suggested:</p>
<blockquote>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span></span>
<span id="cb18-2"><a href="#cb18-2"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>filesystem<span class="op">::</span>path<span class="op">&gt;</span>;</span></code></pre></div>
</blockquote>
<p>But this only handles <code class="sourceCode cpp">std<span class="op">::</span>filesystem<span class="op">::</span>path</code> and would not handle other ranges-of-self (the obvious example here is <code class="sourceCode cpp">boost<span class="op">::</span>filesystem<span class="op">::</span>path</code>). So instead, this paper proposes that we first reject ranges-of-self:</p>
<blockquote>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1"></a><span class="kw">template</span> <span class="op">&lt;</span>range R<span class="op">&gt;</span></span>
<span id="cb19-2"><a href="#cb19-2"></a>    <span class="kw">requires</span> <span class="op">(</span><span class="kw">not</span> same_as<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span>, R<span class="op">&gt;)</span></span>
<span id="cb19-3"><a href="#cb19-3"></a>         <span class="kw">and</span> formattable<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></span>
<span id="cb19-4"><a href="#cb19-4"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>R<span class="op">&gt;</span></span>
<span id="cb19-5"><a href="#cb19-5"></a>    <span class="op">:</span> range_formatter<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></span>
<span id="cb19-6"><a href="#cb19-6"></a><span class="op">{</span> <span class="op">}</span>;</span></code></pre></div>
</blockquote>
<h3 data-number="3.3.6" id="format-specifiers"><span class="header-section-number">3.3.6</span> Format Specifiers<a href="#format-specifiers" class="self-link"></a></h3>
<p>One of (but hardly the only) the great selling points of <code class="sourceCode cpp">format</code> over iostreams is the ability to use specifiers. For instance, from the <code class="sourceCode cpp">fmt</code> documentation:</p>
<blockquote>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1"></a>fmt<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:&lt;30}&quot;</span>, <span class="st">&quot;left aligned&quot;</span><span class="op">)</span>;</span>
<span id="cb20-2"><a href="#cb20-2"></a><span class="co">// Result: &quot;left aligned                  &quot;</span></span>
<span id="cb20-3"><a href="#cb20-3"></a>fmt<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:&gt;30}&quot;</span>, <span class="st">&quot;right aligned&quot;</span><span class="op">)</span>;</span>
<span id="cb20-4"><a href="#cb20-4"></a><span class="co">// Result: &quot;                 right aligned&quot;</span></span>
<span id="cb20-5"><a href="#cb20-5"></a>fmt<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:^30}&quot;</span>, <span class="st">&quot;centered&quot;</span><span class="op">)</span>;</span>
<span id="cb20-6"><a href="#cb20-6"></a><span class="co">// Result: &quot;           centered           &quot;</span></span>
<span id="cb20-7"><a href="#cb20-7"></a>fmt<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:*^30}&quot;</span>, <span class="st">&quot;centered&quot;</span><span class="op">)</span>;  <span class="co">// use &#39;*&#39; as a fill char</span></span>
<span id="cb20-8"><a href="#cb20-8"></a><span class="co">// Result: &quot;***********centered***********&quot;</span></span></code></pre></div>
</blockquote>
<p>Earlier revisions of this paper suggested that formatting ranges and tuples would accept no format specifiers, but there indeed are quite a few things we may want to do here (as by Tomasz Kamiński and Peter Dimov):</p>
<ul>
<li>Formatting a range of pairs as a map (the <code class="sourceCode cpp">key<span class="op">:</span> value</code> syntax rather than the <code class="sourceCode cpp"><span class="op">(</span>key, value<span class="op">)</span></code> one)</li>
<li>Formatting a range of chars as a string (i.e. to print <code class="x">hello</code> or <code class="x">&quot;hello&quot;</code> rather than <code class="x">[&#39;h&#39;, &#39;e&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;]</code>)</li>
</ul>
<p>But these are just providing a specifier for how we format the range itself. How about how we format the elements of the range? Can I conveniently format a range of integers, printing their values as hex? Or as characters? Or print a range of chrono time points in whatever format I want? That’s fairly powerful.</p>
<p>The problem is how do we actually <em>do that</em>. After a lengthy discussion with Peter Dimov, Tim Song, and Victor Zverovich, this is what we came up with. I’ll start with a table of examples and follow up with a more detailed explanation.</p>
<p>Instead of writing a bunch of examples like <code class="sourceCode cpp">print<span class="op">(</span><span class="st">&quot;{:?}</span><span class="sc">\n</span><span class="st">&quot;</span>, v<span class="op">)</span></code>, I’m just displaying the format string in one column (the <code class="sourceCode cpp"><span class="st">&quot;{:?}&quot;</span></code> here) and the argument in another (the <code class="sourceCode cpp">v</code>):</p>
<table>
<colgroup>
<col style="width: 14%"></col>
<col style="width: 42%"></col>
<col style="width: 42%"></col>
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Format String</strong>
</div></th>
<th><div style="text-align:center">
<strong>Contents</strong>
</div></th>
<th><div style="text-align:center">
<strong>Formatted Output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="x">{:}</code></td>
<td><code class="sourceCode cpp"><span class="dv">42</span></code></td>
<td><code class="x">42</code></td>
</tr>
<tr class="even">
<td><code class="x">{:#x}</code></td>
<td><code class="sourceCode cpp"><span class="dv">42</span></code></td>
<td><code class="x">0x2a</code></td>
</tr>
<tr class="odd">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp"><span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span></code></td>
<td><code class="x">h    llo</code></td>
</tr>
<tr class="even">
<td><code class="x">{:?}</code></td>
<td><code class="sourceCode cpp"><span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span></code></td>
<td><code class="x">&quot;h\tllo&quot;</code></td>
</tr>
<tr class="odd">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span><span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span>, <span class="st">&quot;world&quot;</span><span class="bu">s</span><span class="op">}</span></code></td>
<td><code class="x">[&quot;h\tllo&quot;, &quot;world&quot;]</code></td>
</tr>
<tr class="even">
<td><code class="x">{:}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span><span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span>, <span class="st">&quot;world&quot;</span><span class="bu">s</span><span class="op">}</span></code></td>
<td><code class="x">[&quot;h\tllo&quot;, &quot;world&quot;]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span><span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span>, <span class="st">&quot;world&quot;</span><span class="bu">s</span><span class="op">}</span></code></td>
<td><code class="x">[h    llo, world]</code></td>
</tr>
<tr class="even">
<td><code class="x">{:*^14}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span><span class="st">&quot;he&quot;</span><span class="bu">s</span>, <span class="st">&quot;wo&quot;</span><span class="bu">s</span><span class="op">}</span></code></td>
<td><code class="x">*[&quot;he&quot;, &quot;wo&quot;]*</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::*^14}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span><span class="st">&quot;he&quot;</span><span class="bu">s</span>, <span class="st">&quot;wo&quot;</span><span class="bu">s</span><span class="op">}</span></code></td>
<td><code class="x">[******he******, ******wo******]</code></td>
</tr>
<tr class="even">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[&#39;H&#39;, &#39;\t&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[H,     , l, l, o]</code></td>
</tr>
<tr class="even">
<td><code class="x">{::c}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[H,     , l, l, o]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::?c}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[&#39;H&#39;, &#39;\t&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;]</code></td>
</tr>
<tr class="even">
<td><code class="x">{::d}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[72, 9, 108, 108, 111]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::#x}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[0x48, 0x9, 0x6c, 0x6c, 0x6f]</code></td>
</tr>
<tr class="even">
<td><code class="x">{:s}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">H    llo</code></td>
</tr>
<tr class="odd">
<td><code class="x">{:?s}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">&quot;H\tllo&quot;</code></td>
</tr>
<tr class="even">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">pair<span class="op">{</span><span class="dv">42</span>, <span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span><span class="op">}</span></code></td>
<td><code class="x">(42, &quot;h\tllo&quot;)</code></td>
</tr>
<tr class="odd">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span>pair<span class="op">{</span><span class="dv">42</span>, <span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span><span class="op">}}</span></code></td>
<td><code class="x">[(42, &quot;h\tllo&quot;)]</code></td>
</tr>
<tr class="even">
<td><code class="x">{:m}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span>pair<span class="op">{</span><span class="dv">42</span>, <span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span><span class="op">}}</span></code></td>
<td><code class="x">{42: &quot;h\tllo&quot;}</code></td>
</tr>
<tr class="odd">
<td><code class="x">{:m:}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span>pair<span class="op">{</span><span class="dv">42</span>, <span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span><span class="op">}}</span></code></td>
<td><code class="x">{42: h    llo}</code></td>
</tr>
<tr class="even">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span>vector<span class="op">{</span><span class="ch">&#39;a&#39;</span><span class="op">}</span>, vector<span class="op">{</span><span class="ch">&#39;b&#39;</span>, <span class="ch">&#39;c&#39;</span><span class="op">}}</span></code></td>
<td><code class="x">[[&#39;a&#39;], [&#39;b&#39;, &#39;c&#39;]]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::?s}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span>vector<span class="op">{</span><span class="ch">&#39;a&#39;</span><span class="op">}</span>, vector<span class="op">{</span><span class="ch">&#39;b&#39;</span>, <span class="ch">&#39;c&#39;</span><span class="op">}}</span></code></td>
<td><code class="x">[&quot;a&quot;, &quot;bc&quot;]</code></td>
</tr>
<tr class="even">
<td><code class="x">{:::d}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span>vector<span class="op">{</span><span class="ch">&#39;a&#39;</span><span class="op">}</span>, vector<span class="op">{</span><span class="ch">&#39;b&#39;</span>, <span class="ch">&#39;c&#39;</span><span class="op">}}</span></code></td>
<td><code class="x">[[97], [98, 99]]</code></td>
</tr>
</tbody>
</table>
<h3 data-number="3.3.7" id="explanation-of-added-specifiers"><span class="header-section-number">3.3.7</span> Explanation of Added Specifiers<a href="#explanation-of-added-specifiers" class="self-link"></a></h3>
<h4 data-number="3.3.7.1" id="the-debug-specifier"><span class="header-section-number">3.3.7.1</span> The debug specifier <code class="sourceCode cpp"><span class="op">?</span></code><a href="#the-debug-specifier" class="self-link"></a></h4>
<p><code class="sourceCode cpp"><span class="dt">char</span></code> and <code class="sourceCode cpp">string</code> and <code class="sourceCode cpp">string_view</code> will start to support the <code class="sourceCode cpp"><span class="op">?</span></code> specifier. This will cause the character/string to be printed as quoted (characters with <code class="sourceCode cpp"><span class="ch">&#39;</span></code> and strings with <code class="sourceCode cpp"><span class="st">&quot;</span></code>) and all characters to be escaped, as <a href="char-and-string-and-other-string-like-types-in-ranges-or-tuples">described earlier</a>.</p>
<p>This facility will be generated by the formatters for these types providing an addition member function (on top of <code class="sourceCode cpp">parse</code> and <code class="sourceCode cpp">format</code>):</p>
<blockquote>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1"></a><span class="dt">void</span> set_debug_format<span class="op">()</span>;</span></code></pre></div>
</blockquote>
<p>Which other formatting types may conditionally invoke when they parse a <code class="sourceCode cpp"><span class="op">?</span></code>. For instance, since the intent is that range formatters print escaped by default, the logic for a simple range formatter that accepts no specifiers might look like this (note that this paper is proposing something more complicated than this, this is just an example):</p>
<blockquote>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> V<span class="op">&gt;</span></span>
<span id="cb22-2"><a href="#cb22-2"></a><span class="kw">struct</span> range_formatter <span class="op">{</span></span>
<span id="cb22-3"><a href="#cb22-3"></a>    std<span class="op">::</span>formatter<span class="op">&lt;</span>V<span class="op">&gt;</span> underlying;</span>
<span id="cb22-4"><a href="#cb22-4"></a></span>
<span id="cb22-5"><a href="#cb22-5"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> ParseContext<span class="op">&gt;</span></span>
<span id="cb22-6"><a href="#cb22-6"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> parse<span class="op">(</span>ParseContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-7"><a href="#cb22-7"></a>        <span class="co">// ensure that the format specifier is empty</span></span>
<span id="cb22-8"><a href="#cb22-8"></a>        <span class="cf">if</span> <span class="op">(</span>ctx<span class="op">.</span>begin<span class="op">()</span> <span class="op">!=</span> ctx<span class="op">.</span>end<span class="op">()</span> <span class="op">&amp;&amp;</span> <span class="op">*</span>ctx<span class="op">.</span>begin<span class="op">()</span> <span class="op">!=</span> <span class="ch">&#39;}&#39;</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-9"><a href="#cb22-9"></a>            <span class="cf">throw</span> std<span class="op">::</span>format_error<span class="op">(</span><span class="st">&quot;invalid format&quot;</span><span class="op">)</span>;</span>
<span id="cb22-10"><a href="#cb22-10"></a>        <span class="op">}</span></span>
<span id="cb22-11"><a href="#cb22-11"></a></span>
<span id="cb22-12"><a href="#cb22-12"></a>        <span class="co">// ensure that the underlying type can parse an empty specifier</span></span>
<span id="cb22-13"><a href="#cb22-13"></a>        <span class="kw">auto</span> out <span class="op">=</span> underlying<span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb22-14"><a href="#cb22-14"></a></span>
<span id="cb22-15"><a href="#cb22-15"></a>        <span class="co">// conditionally format as debug, if the type supports it</span></span>
<span id="cb22-16"><a href="#cb22-16"></a>        <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">requires</span> <span class="op">{</span> underlying<span class="op">.</span>set_debug_format<span class="op">()</span>; <span class="op">})</span> <span class="op">{</span></span>
<span id="cb22-17"><a href="#cb22-17"></a>            underlying<span class="op">.</span>set_debug_format<span class="op">()</span>;</span>
<span id="cb22-18"><a href="#cb22-18"></a>        <span class="op">}</span></span>
<span id="cb22-19"><a href="#cb22-19"></a>        <span class="cf">return</span> out;</span>
<span id="cb22-20"><a href="#cb22-20"></a>    <span class="op">}</span></span>
<span id="cb22-21"><a href="#cb22-21"></a></span>
<span id="cb22-22"><a href="#cb22-22"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R, <span class="kw">typename</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb22-23"><a href="#cb22-23"></a>        <span class="kw">requires</span> std<span class="op">::</span>same_as<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span>, V<span class="op">&gt;</span></span>
<span id="cb22-24"><a href="#cb22-24"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> format<span class="op">(</span>R<span class="op">&amp;&amp;</span> r, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-25"><a href="#cb22-25"></a>        <span class="kw">auto</span> out <span class="op">=</span> ctx<span class="op">.</span>out<span class="op">()</span>;</span>
<span id="cb22-26"><a href="#cb22-26"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;[&#39;</span>;</span>
<span id="cb22-27"><a href="#cb22-27"></a>        <span class="kw">auto</span> first <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb22-28"><a href="#cb22-28"></a>        <span class="kw">auto</span> last <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>end<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb22-29"><a href="#cb22-29"></a>        <span class="cf">if</span> <span class="op">(</span>first <span class="op">!=</span> last<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-30"><a href="#cb22-30"></a>            <span class="co">// have to format every element via the underlying formatter</span></span>
<span id="cb22-31"><a href="#cb22-31"></a>            ctx<span class="op">.</span>advance_to<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>out<span class="op">))</span>;</span>
<span id="cb22-32"><a href="#cb22-32"></a>            out <span class="op">=</span> underlying<span class="op">.</span>format<span class="op">(*</span>first, ctx<span class="op">)</span>;</span>
<span id="cb22-33"><a href="#cb22-33"></a>            <span class="cf">for</span> <span class="op">(++</span>first; first <span class="op">!=</span> last; <span class="op">++</span>first<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-34"><a href="#cb22-34"></a>                <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;,&#39;</span>;</span>
<span id="cb22-35"><a href="#cb22-35"></a>                <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39; &#39;</span>;</span>
<span id="cb22-36"><a href="#cb22-36"></a>                ctx<span class="op">.</span>advance_to<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>out<span class="op">))</span>;</span>
<span id="cb22-37"><a href="#cb22-37"></a>                out <span class="op">=</span> underlying<span class="op">.</span>format<span class="op">(*</span>first, ctx<span class="op">)</span>;</span>
<span id="cb22-38"><a href="#cb22-38"></a>            <span class="op">}</span></span>
<span id="cb22-39"><a href="#cb22-39"></a>        <span class="op">}</span></span>
<span id="cb22-40"><a href="#cb22-40"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;]&#39;</span>;</span>
<span id="cb22-41"><a href="#cb22-41"></a>        <span class="cf">return</span> out;</span>
<span id="cb22-42"><a href="#cb22-42"></a>    <span class="op">}</span></span>
<span id="cb22-43"><a href="#cb22-43"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<h4 data-number="3.3.7.2" id="range-specifiers"><span class="header-section-number">3.3.7.2</span> Range specifiers<a href="#range-specifiers" class="self-link"></a></h4>
<p>Range format specifiers come in two kinds: specifiers for the range itself and specifiers for the underlying elements of the range. They must be provided in order: the range specifiers (optionally), then if desired, a colon and then the underlying specifier (optionally). For instance:</p>
<table>
<colgroup>
<col style="width: 20%"></col>
<col style="width: 80%"></col>
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>specifier</strong>
</div></th>
<th><div style="text-align:center">
<strong>meaning</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="x">{}</code></td>
<td>No specifiers</td>
</tr>
<tr class="even">
<td><code class="x">{:}</code></td>
<td>No specifiers</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp"><span class="op">{:&lt;</span><span class="dv">10</span><span class="op">}</span></code></td>
<td>The whole range formatting is left-aligned, with a width of 10</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp"><span class="op">{:*^</span><span class="dv">20</span><span class="op">}</span></code></td>
<td>The whole range formatting is center-aligned, with a width of 20, padded with <code class="sourceCode cpp"><span class="op">*</span></code>s</td>
</tr>
<tr class="odd">
<td><code class="x">{:m}</code></td>
<td>Apply the <code class="sourceCode cpp">m</code> specifier to the range (which must be a range of pair or 2-tuple)</td>
</tr>
<tr class="even">
<td><code class="x">{::d}</code></td>
<td>Apply the <code class="sourceCode cpp">d</code> specifier to each element of the range</td>
</tr>
<tr class="odd">
<td><code class="x">{:?s}</code></td>
<td>Apply the <code class="sourceCode cpp"><span class="op">?</span>s</code> specifier to the range (which must be a range of char)</td>
</tr>
</tbody>
</table>
<p>There are only a few top-level range-specific specifiers proposed:</p>
<ul>
<li><code class="sourceCode cpp">s</code>: for ranges of char, only: formats the range as a string.</li>
<li><code class="sourceCode cpp"><span class="op">?</span>s</code> for ranges of char, only: same as <code class="sourceCode cpp">s</code> except will additionally quote and escape the string</li>
<li><code class="sourceCode cpp">m</code>: for ranges of <code class="sourceCode cpp">pair</code>s (or <code class="sourceCode cpp">tuple</code>s of size 2) will format as <code class="sourceCode cpp"><span class="op">{</span>k1<span class="op">:</span> v1, k2<span class="op">:</span> v2<span class="op">}</span></code> instead of <code class="sourceCode cpp"><span class="op">[(</span>k1, v1<span class="op">)</span>, <span class="op">(</span>k2, v2<span class="op">)]</span></code> (i.e. as a <code class="sourceCode cpp">map</code>).</li>
<li><code class="sourceCode cpp">e</code>: will format without the brackets. This will let you, for instance, format a range as <code class="sourceCode cpp">a, b, c</code> or <code class="sourceCode cpp"><span class="op">{</span>a, b, c<span class="op">}</span></code> or <code class="sourceCode cpp"><span class="op">(</span>a, b, c<span class="op">)</span></code> or however else you want, simply by providing the desired format string. If printing a normal range, the brackets removed are <code class="sourceCode cpp"><span class="op">[]</span></code>. If printing as a map, the brackets removed are <code class="sourceCode cpp"><span class="op">{}</span></code>. If printing as a quoted string, the brackets removed are the <code class="sourceCode cpp"><span class="st">&quot;&quot;</span></code>s (but escaping will still happen).</li>
<li><code class="sourceCode cpp">d</code>: either a <a href="#dynamic-delimiter-for-ranges">dynamic delimiter</a> or <a href="#static-delimiter-for-ranges">static delimiter</a>, depending on what follows the <code class="sourceCode cpp">d</code>. See those sections for more detail.</li>
</ul>
<p>Additionally, ranges will support the same fill/align/width specifiers as in <em>std-format-spec</em>, for convenience and consistency.</p>
<p>If no element-specific formatter is provided (i.e. there is no inner colon - an empty element-specific formatter is still an element-specific formatter), the range will be formatted as debug. Otherwise, the element-specific formatter will be parsed and used.</p>
<p>To revisit a few rows from the earlier table:</p>
<table>
<colgroup>
<col style="width: 11%"></col>
<col style="width: 44%"></col>
<col style="width: 44%"></col>
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Format String</strong>
</div></th>
<th><div style="text-align:center">
<strong>Contents</strong>
</div></th>
<th><div style="text-align:center">
<strong>Formatted Output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[&#39;H&#39;, &#39;\t&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;]</code></td>
</tr>
<tr class="even">
<td><code class="x">{::}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[H,     , l, l, o]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::?c}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[&#39;H&#39;, &#39;\t&#39;, &#39;l&#39;, &#39;l&#39;, &#39;o&#39;]</code></td>
</tr>
<tr class="even">
<td><code class="x">{::d}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[72, 9, 108, 108, 111]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::#x}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">[0x48, 0x9, 0x6c, 0x6c, 0x6f]</code></td>
</tr>
<tr class="even">
<td><code class="x">{:s}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">H    llo</code></td>
</tr>
<tr class="odd">
<td><code class="x">{:?s}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;{</span><span class="ch">&#39;H&#39;</span>, <span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;l&#39;</span>, <span class="ch">&#39;o&#39;</span><span class="op">}</span></code></td>
<td><code class="x">&quot;H\tllo&quot;</code></td>
</tr>
<tr class="even">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span>vector<span class="op">{</span><span class="ch">&#39;a&#39;</span><span class="op">}</span>, vector<span class="op">{</span><span class="ch">&#39;b&#39;</span>, <span class="ch">&#39;c&#39;</span><span class="op">}}</span></code></td>
<td><code class="x">[[&#39;a&#39;], [&#39;b&#39;, &#39;c&#39;]]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::?s}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span>vector<span class="op">{</span><span class="ch">&#39;a&#39;</span><span class="op">}</span>, vector<span class="op">{</span><span class="ch">&#39;b&#39;</span>, <span class="ch">&#39;c&#39;</span><span class="op">}}</span></code></td>
<td><code class="x">[&quot;a&quot;, &quot;bc&quot;]</code></td>
</tr>
<tr class="even">
<td><code class="x">{:::d}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">{</span>vector<span class="op">{</span><span class="ch">&#39;a&#39;</span><span class="op">}</span>, vector<span class="op">{</span><span class="ch">&#39;b&#39;</span>, <span class="ch">&#39;c&#39;</span><span class="op">}}</span></code></td>
<td><code class="x">[[97], [98, 99]]</code></td>
</tr>
</tbody>
</table>
<p>The second row is not printed quoted, because an empty element specifier is provided. We assume that if the user explicitly provides a format specifier (even if it’s empty), that they want control over what they’re doing. The third row is printed quoted again because it was explicitly asked for using the <code class="sourceCode cpp"><span class="op">?</span>c</code> specifier, applied to each character.</p>
<p>The last row, <code class="sourceCode cpp"><span class="op">:::</span>d</code>, is parsed as:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th><div style="text-align:center">
<strong>top level outer vector</strong>
</div></th>
<th></th>
<th><div style="text-align:center">
<strong>top level inner vector</strong>
</div></th>
<th></th>
<th><div style="text-align:center">
<strong>inner vector each element</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp"><span class="op">:</span></code></td>
<td>(none)</td>
<td><code class="sourceCode cpp"><span class="op">:</span></code></td>
<td>(none)</td>
<td><code class="sourceCode cpp"><span class="op">:</span></code></td>
<td><code class="sourceCode cpp">d</code></td>
</tr>
</tbody>
</table>
<p>That is, the <code class="sourceCode cpp">d</code> format specifier is applied to each underlying <code class="sourceCode cpp"><span class="dt">char</span></code>, which causes them to be printed as integers instead of characters.</p>
<p>Note that you can provide both a fill/align/width specifier to the range itself as well as to each element:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Format String</strong>
</div></th>
<th><div style="text-align:center">
<strong>Contents</strong>
</div></th>
<th><div style="text-align:center">
<strong>Formatted Output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code></td>
<td><code class="x">[1, 2, 3]</code></td>
</tr>
<tr class="even">
<td><code class="x">{::*^5}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code></td>
<td><code class="x">[**1**, **2**, **3**]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{:o^17}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code></td>
<td><code class="x">oooo[1, 2, 3]oooo</code></td>
</tr>
<tr class="even">
<td><code class="x">{:o^29:*^5}</code></td>
<td><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span></code></td>
<td><code class="x">oooo[**1**, **2**, **3**]oooo</code></td>
</tr>
</tbody>
</table>
<h4 data-number="3.3.7.3" id="dynamic-delimiter-for-ranges"><span class="header-section-number">3.3.7.3</span> Dynamic Delimiter for Ranges<a href="#dynamic-delimiter-for-ranges" class="self-link"></a></h4>
<p>Let’s say I have a <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">uint8_t</span><span class="op">&gt;</span></code> that I wish to format as a MAC address. That is, I want to print every element with <code class="sourceCode cpp"><span class="st">&quot;02x&quot;</span></code>, delimited with <code class="sourceCode cpp"><span class="st">&quot;:&quot;</span></code> (rather than the default <code class="sourceCode cpp"><span class="st">&quot;, &quot;</span></code>), and without the surrounding square brackets.</p>
<p>I showed an example of how to do this earlier using <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code>:</p>
<blockquote>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">uint8_t</span><span class="op">&gt;</span> mac <span class="op">=</span> <span class="op">{</span><span class="bn">0xaa</span>, <span class="bn">0xbb</span>, <span class="bn">0xcc</span>, <span class="bn">0xdd</span>, <span class="bn">0xee</span>, <span class="bn">0xff</span><span class="op">}</span>;</span>
<span id="cb23-2"><a href="#cb23-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}</span><span class="sc">\n</span><span class="st">&quot;</span>, mac<span class="op">)</span>;                     <span class="co">// [170, 187, 204, 221, 238, 255]</span></span>
<span id="cb23-3"><a href="#cb23-3"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, fmt<span class="op">::</span>join<span class="op">(</span>mac, <span class="st">&quot;:&quot;</span><span class="op">))</span>; <span class="co">// aa:bb:cc:dd:ee:ff</span></span></code></pre></div>
</blockquote>
<p>However, if we’re going to add more support for adding specifiers to ranges, that suggests a potential alternate avenue. We could add a dynamic delimiter in the same way that we support dynamic width in other contexts. That is:</p>
<blockquote>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed{}:02x}&quot;</span>, mac, <span class="st">&quot;:&quot;</span><span class="op">)</span>; <span class="co">// aa:bb:cc:dd:ee:ff</span></span></code></pre></div>
</blockquote>
<p>Here, <code class="sourceCode cpp"><span class="st">&quot;:ed{}&quot;</span></code> are the specifiers for the top-level vector, and then <code class="sourceCode cpp"><span class="st">&quot;:02x&quot;</span></code> are the specifiers for the underlying element. The <code class="sourceCode cpp">e</code> specifier (for empty brackets) avoids printing the <code class="sourceCode cpp"><span class="op">[]</span></code>s and then the <code class="sourceCode cpp">d</code> specifier (for delimiter) is followed by which argument to get the delimiter out of (<code class="sourceCode cpp"><span class="op">{}</span></code> for auto-numbering, could also have been <code class="sourceCode cpp"><span class="op">{</span><span class="dv">1</span><span class="op">}</span></code> in this example).</p>
<p>Perhaps <code class="sourceCode cpp">e</code> is implicit with <code class="sourceCode cpp">d</code>, perhaps not.</p>
<p>The question is, there are ultimately two ways that we could format this mac address as a result of this paper:</p>
<blockquote>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, fmt<span class="op">::</span>join<span class="op">(</span>mac, <span class="st">&quot;:&quot;</span><span class="op">))</span>; <span class="co">// aa:bb:cc:dd:ee:ff</span></span>
<span id="cb25-2"><a href="#cb25-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed{}:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, mac, <span class="st">&quot;:&quot;</span><span class="op">)</span>;       <span class="co">// aa:bb:cc:dd:ee:ff</span></span></code></pre></div>
</blockquote>
<p>Do we want to pursue:</p>
<ol type="1">
<li>Just <code class="sourceCode cpp">fmt<span class="op">::</span>join</code>?</li>
<li>Just dynamic delimiter?</li>
<li>Both?</li>
</ol>
<p>The dynamic delimiter approach is more cryptic. The <code class="sourceCode cpp">join</code> approach arguably has the advantage of making it more clear what the delimiter is and how it’s used, whereas in the dynamic delimiter approach it’s just… wherever. I’ll discuss <a href="#static-delimiter-for-ranges">static delimiters</a> shortly.</p>
<p>The dynamic delimiter approach is also limited to <em>just</em> allowing <code class="sourceCode cpp">charT</code>, <code class="sourceCode cpp">charT <span class="kw">const</span><span class="op">*</span></code>, and <code class="sourceCode cpp">basic_string_view<span class="op">&lt;</span>charT<span class="op">&gt;</span></code> (and maybe <code class="sourceCode cpp">basic_string<span class="op">&lt;</span>charT<span class="op">&gt;</span></code>) as delimiter types. The <code class="sourceCode cpp">fmt<span class="op">::</span>join</code> approach would allow any type convertible to <code class="sourceCode cpp">basic_string_view<span class="op">&lt;</span>charT<span class="op">&gt;</span></code>. This is a consequence of <code class="sourceCode cpp">fmt<span class="op">::</span>join</code> being a function that accepts a <code class="sourceCode cpp">string_view</code> argument, while going through <code class="sourceCode cpp">format</code> directly can’t do any sort of conversions - we have to use the type-erased arguments, and we simply cannot know if some user-defined type would have been convertible to <code class="sourceCode cpp">string_view</code>.</p>
<p>But the dynamic delimiter approach has advantages too.</p>
<p>First, it naturally nests. So if I wanted to format a <em>range</em> of mac addresses, I can do that:</p>
<blockquote>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1"></a><span class="co">// one mac</span></span>
<span id="cb26-2"><a href="#cb26-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed{}:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, one_mac, <span class="st">&quot;:&quot;</span><span class="op">)</span>;</span>
<span id="cb26-3"><a href="#cb26-3"></a><span class="co">// range of macs</span></span>
<span id="cb26-4"><a href="#cb26-4"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{::ed{}:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, some_macs, <span class="st">&quot;:&quot;</span><span class="op">)</span>;</span>
<span id="cb26-5"><a href="#cb26-5"></a><span class="co">// range of range of macs</span></span>
<span id="cb26-6"><a href="#cb26-6"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:::ed{}:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, uber_macs, <span class="st">&quot;:&quot;</span><span class="op">)</span>;</span>
<span id="cb26-7"><a href="#cb26-7"></a><span class="co">// range of range of macs, providing all three delimiters</span></span>
<span id="cb26-8"><a href="#cb26-8"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed{}:ed{}:ed{}:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, uber_macs, <span class="st">&quot;++&quot;</span>, <span class="st">&quot;**&quot;</span>, <span class="st">&quot;:&quot;</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>Whereas this is much more awkward with <code class="sourceCode cpp">fmt<span class="op">::</span>join</code>:</p>
<blockquote>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1"></a><span class="co">// one mac</span></span>
<span id="cb27-2"><a href="#cb27-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, fmt<span class="op">::</span>join<span class="op">(</span>one_mac, <span class="st">&quot;:&quot;</span><span class="op">))</span>;</span>
<span id="cb27-3"><a href="#cb27-3"></a><span class="co">// range of macs</span></span>
<span id="cb27-4"><a href="#cb27-4"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{::02x}</span><span class="sc">\n</span><span class="st">&quot;</span>,</span>
<span id="cb27-5"><a href="#cb27-5"></a>    some_macs <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> m<span class="op">){</span></span>
<span id="cb27-6"><a href="#cb27-6"></a>        <span class="cf">return</span> fmt<span class="op">::</span>join<span class="op">(</span>m, <span class="st">&quot;:&quot;</span><span class="op">)</span>;</span>
<span id="cb27-7"><a href="#cb27-7"></a>    <span class="op">}))</span>;</span>
<span id="cb27-8"><a href="#cb27-8"></a><span class="co">// range of range of macs</span></span>
<span id="cb27-9"><a href="#cb27-9"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:::02x}</span><span class="sc">\n</span><span class="st">&quot;</span>,</span>
<span id="cb27-10"><a href="#cb27-10"></a>    uber_macs <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> m<span class="op">){</span></span>
<span id="cb27-11"><a href="#cb27-11"></a>        <span class="cf">return</span> m <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> m2<span class="op">){</span></span>
<span id="cb27-12"><a href="#cb27-12"></a>            <span class="cf">return</span> fmt<span class="op">::</span>join<span class="op">(</span>m2, <span class="st">&quot;:&quot;</span><span class="op">)</span>;</span>
<span id="cb27-13"><a href="#cb27-13"></a>        <span class="op">})</span>;</span>
<span id="cb27-14"><a href="#cb27-14"></a>    <span class="op">}))</span>;</span>
<span id="cb27-15"><a href="#cb27-15"></a><span class="co">// range of range of macs, providing all three delimiters</span></span>
<span id="cb27-16"><a href="#cb27-16"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>,</span>
<span id="cb27-17"><a href="#cb27-17"></a>    fmt<span class="op">::</span>join<span class="op">(</span>uber_macs <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> m<span class="op">){</span></span>
<span id="cb27-18"><a href="#cb27-18"></a>        <span class="cf">return</span> fmt<span class="op">::</span>join<span class="op">(</span>m <span class="op">|</span> std<span class="op">::</span>views<span class="op">::</span>transform<span class="op">([](</span><span class="kw">auto</span><span class="op">&amp;&amp;</span> m2<span class="op">){</span></span>
<span id="cb27-19"><a href="#cb27-19"></a>            <span class="cf">return</span> fmt<span class="op">::</span>join<span class="op">(</span>m2, <span class="st">&quot;:&quot;</span><span class="op">)</span>;</span>
<span id="cb27-20"><a href="#cb27-20"></a>        <span class="op">})</span>, <span class="st">&quot;**&quot;</span><span class="op">)</span>;</span>
<span id="cb27-21"><a href="#cb27-21"></a>    <span class="op">})</span>,</span>
<span id="cb27-22"><a href="#cb27-22"></a>    <span class="st">&quot;++&quot;</span><span class="op">))</span>;</span></code></pre></div>
</blockquote>
<p>The dynamic delimiter approach also supports more functionality. If I want to center-align the mac address and pad it with asterisks like I’ve been doing with every other example (for instance), that’s just more specifiers as compared with another call to <code class="sourceCode cpp">format</code>:</p>
<blockquote>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:*^23ed{}:02x}</span><span class="sc">\n</span><span class="st">&quot;</span>, mac, <span class="st">&quot;:&quot;</span><span class="op">)</span>;                            <span class="co">// ***aa:bb:cc:dd:ee:ff***</span></span>
<span id="cb28-2"><a href="#cb28-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:*^23}</span><span class="sc">\n</span><span class="st">&quot;</span>, fmt<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:02x}&quot;</span>, fmt<span class="op">::</span>join<span class="op">(</span>mac, <span class="st">&quot;:&quot;</span><span class="op">)))</span>;  <span class="co">// ***aa:bb:cc:dd:ee:ff***</span></span></code></pre></div>
</blockquote>
<p>And the other advantage is that it’s one less thing to have to specify. And part of the problem there is what to name <code class="sourceCode cpp">fmt<span class="op">::</span>join</code>? This paper has been using the name <code class="sourceCode cpp">std<span class="op">::</span>format_join</code>. Is this one of those cases that Bjarne likes to point out as people want more syntax because it’s simply novel, or is this one of those cases where the terser syntax is just inscrutable and unnecessary?</p>
<p>I was initially torn on dynamic delimiter, but after spending even a little bit of time working with them in the contexts of this paper, I have become a big fan. I don’t actually think <code class="sourceCode cpp">fmt<span class="op">::</span>join</code> adds anything. In <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code>, formatting ranges wouldn’t accept specifiers for each element, so <code class="sourceCode cpp">join</code> there solved two problems: adding element-specific specifiers and a custom delimiter. But this paper is already expanding the <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> functionality by allowing specifiers in direct range formatting, adding delimiters there seems in line with that further enhancement.</p>
<p>In fact, we can even go further…</p>
<h4 data-number="3.3.7.4" id="static-delimiter-for-ranges"><span class="header-section-number">3.3.7.4</span> Static Delimiter for Ranges<a href="#static-delimiter-for-ranges" class="self-link"></a></h4>
<p>I just showed the idea that we might be able to support:</p>
<blockquote>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed{}:02x}&quot;</span>, mac, <span class="st">&quot;:&quot;</span><span class="op">)</span>;  <span class="co">// aa:bb:cc:dd:ee:ff</span></span></code></pre></div>
</blockquote>
<p>But practically speaking, it is extremely common to know, statically, what the delimiter is. And a lot of the time the delimiter is going to be either empty (<code class="sourceCode cpp"><span class="st">&quot;&quot;</span></code>) or a single character, as opposed to the default <code class="sourceCode cpp"><span class="st">&quot;, &quot;</span></code>. In these cases, having a dynamic delimiter seems like pure overhead.</p>
<p>Now the question is, how could we do a static delimiter (i.e. built into the specifier) rather than a dynamic delimiter (i.e. provided as a format argument)? The issue here is we need bounds - the same kinds of bounds we need for pair/tuple. So a starting point might be… let’s just use <code class="sourceCode cpp"><span class="op">[]</span></code>s. The stuff between the <code class="sourceCode cpp"><span class="op">[]</span></code>s is the delimiter:</p>
<blockquote>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1"></a><span class="co">// dynamic delimiter, single colon</span></span>
<span id="cb30-2"><a href="#cb30-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed{}:02x}&quot;</span>, mac, <span class="st">&quot;:&quot;</span><span class="op">)</span>; <span class="co">// aa:bb:cc:dd:ee:ff</span></span>
<span id="cb30-3"><a href="#cb30-3"></a></span>
<span id="cb30-4"><a href="#cb30-4"></a><span class="co">// static delimiter, different amounts of colons</span></span>
<span id="cb30-5"><a href="#cb30-5"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed[:]:02x}&quot;</span>, mac<span class="op">)</span>;     <span class="co">// aa:bb:cc:dd:ee:ff</span></span>
<span id="cb30-6"><a href="#cb30-6"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed[]:02x}&quot;</span>, mac<span class="op">)</span>;      <span class="co">// aabbccddeeff</span></span>
<span id="cb30-7"><a href="#cb30-7"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed[::]:02x}&quot;</span>, mac<span class="op">)</span>;    <span class="co">// aa::bb::cc::dd::ee::ff</span></span>
<span id="cb30-8"><a href="#cb30-8"></a></span>
<span id="cb30-9"><a href="#cb30-9"></a><span class="co">// dynamic delimiter, brackets for whatever reason</span></span>
<span id="cb30-10"><a href="#cb30-10"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed{}:02x}&quot;</span>, mac, <span class="st">&quot;[]&quot;</span><span class="op">)</span>; <span class="co">// aa[]bb[]cc[]dd[]ee[]ff</span></span></code></pre></div>
</blockquote>
<p>That is, grammatically, <code class="sourceCode cpp">d<span class="op">{}</span></code> or <code class="sourceCode cpp">d<span class="op">{</span><span class="dv">4</span><span class="op">}</span></code> is a dynamic delimiter (referring to the next or 5th argument, respectively), while <code class="sourceCode cpp">d<span class="op">[]</span></code> or <code class="sourceCode cpp">d<span class="op">[-]</span></code> is a static delimiter (having no delimiter and a single hyphen, respectively). This is easy enough to parse.</p>
<p>Of course, as the last example illustrates, once we pick some arbitrary brackets for this (and at least in this case we can actually pick square brackets), we run into the problem of: what if the user actually wants to use <code class="sourceCode cpp"><span class="op">]</span></code> in their delimiter? Now this makes the specifier much harder to parse or deal with and this quickly becomes the same level of problem as the pair/tuple issue.</p>
<p>This one does have slightly easier solutions, in that we could either:</p>
<ol type="1">
<li>Just not allow <code class="sourceCode cpp"><span class="op">]</span></code> in static delimiters, if they want to do that they have to use a dynamic one</li>
<li>Go the lua/cmake route and rather than use <code class="sourceCode cpp"><span class="op">[</span></code> and <code class="sourceCode cpp"><span class="op">]</span></code> to delimit the static delimiter, use <code class="sourceCode cpp"><span class="op">[=[</span></code> and <code class="sourceCode cpp"><span class="op">]=]</span></code> (except with a variable amount of <code class="sourceCode cpp"><span class="op">=</span></code>s, they just have to match).</li>
<li>Allow any Unicode open bracket (except <code class="sourceCode cpp"><span class="op">{</span></code>), that will then be matched by the corresponding close bracket.</li>
</ol>
<p>Or, in code form:</p>
<blockquote>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1"></a><span class="co">// option 1)</span></span>
<span id="cb31-2"><a href="#cb31-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed{}:02x}&quot;</span>, mac, <span class="st">&quot;[]&quot;</span><span class="op">)</span>;      <span class="co">// aa[]bb[]cc[]dd[]ee[]ff</span></span>
<span id="cb31-3"><a href="#cb31-3"></a></span>
<span id="cb31-4"><a href="#cb31-4"></a><span class="co">// option 2) disambiguate by using =&#39;s</span></span>
<span id="cb31-5"><a href="#cb31-5"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed[=[[]]=]:02x}&quot;</span>, mac<span class="op">)</span>;      <span class="co">// aa[]bb[]cc[]dd[]ee[]ff</span></span>
<span id="cb31-6"><a href="#cb31-6"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed[==[[]]==]:02x}&quot;</span>, mac<span class="op">)</span>;    <span class="co">// aa[]bb[]cc[]dd[]ee[]ff</span></span>
<span id="cb31-7"><a href="#cb31-7"></a></span>
<span id="cb31-8"><a href="#cb31-8"></a><span class="co">// .. which pessimizes the typical case</span></span>
<span id="cb31-9"><a href="#cb31-9"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed[[:]]:02x}&quot;</span>, mac<span class="op">)</span>;         <span class="co">// aa:bb:cc:dd:ee:ff</span></span>
<span id="cb31-10"><a href="#cb31-10"></a></span>
<span id="cb31-11"><a href="#cb31-11"></a><span class="co">// option 3) use different brackets:</span></span>
<span id="cb31-12"><a href="#cb31-12"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed([]):02x}&quot;</span>, mac<span class="op">)</span>;          <span class="co">// aa[]bb[]cc[]dd[]ee[]ff</span></span>
<span id="cb31-13"><a href="#cb31-13"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed«[]»:02x}&quot;</span>, mac<span class="op">)</span>;          <span class="co">// aa[]bb[]cc[]dd[]ee[]ff</span></span>
<span id="cb31-14"><a href="#cb31-14"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed⦕[]⦖:02x}&quot;</span>, mac<span class="op">)</span>;          <span class="co">// aa[]bb[]cc[]dd[]ee[]ff</span></span></code></pre></div>
</blockquote>
<p>If we’re going to go the route of static delimiter at all, option 1 seems completely sufficient: if you want to use <code class="sourceCode cpp"><span class="op">]</span></code> in your delimiter, you have to use dynamic delimiter. That seems like an incredibly rare choice of delimiter anyway, not nearly common enough to either pessimize the overwhelmingly common case in terms of what the specifier string looks like or to overcomplicate what the implementation has to do to make it work.</p>
<p>Using a static delimiter, bounded by <code class="sourceCode cpp"><span class="op">[]</span></code>s, does end up being a few characters shorter than using a dynamic delimiter:</p>
<blockquote>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1"></a><span class="co">// format a mac address</span></span>
<span id="cb32-2"><a href="#cb32-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed{}:02x}&quot;</span>, mac, <span class="st">&quot;:&quot;</span><span class="op">)</span>;</span>
<span id="cb32-3"><a href="#cb32-3"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:ed[:]:02x}&quot;</span>, mac<span class="op">)</span>;</span>
<span id="cb32-4"><a href="#cb32-4"></a></span>
<span id="cb32-5"><a href="#cb32-5"></a><span class="co">// join words with a space</span></span>
<span id="cb32-6"><a href="#cb32-6"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:d{}})&quot;</span>, words, <span class="st">&quot; &quot;</span><span class="op">)</span>;</span>
<span id="cb32-7"><a href="#cb32-7"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:d[ ]})&quot;</span>, words<span class="op">)</span>;</span>
<span id="cb32-8"><a href="#cb32-8"></a></span>
<span id="cb32-9"><a href="#cb32-9"></a><span class="co">// .. or with no delimiter</span></span>
<span id="cb32-10"><a href="#cb32-10"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:d{}})&quot;</span>, words, <span class="st">&quot;&quot;</span><span class="op">)</span>;</span>
<span id="cb32-11"><a href="#cb32-11"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:d[]})&quot;</span>, words<span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>But the advantage here isn’t that we’re optimizing for the length of the specifier. The advantage here is that the specifier itself is sufficient to format the argument, so we <em>only</em> have to deal with a single argument. I don’t care about the four fewer characters. I do care about the one fewer argument and the locality of the delimiter.</p>
<p>There would also be a question of how to implement this. Is a <code class="sourceCode cpp">formatter</code> allowed to keep a <code class="sourceCode cpp">string_view</code> into the format specifier (<span class="citation" data-cites="LWG3651">[<a href="#ref-LWG3651" role="doc-biblioref">LWG3651</a>]</span>), to be used in <code class="sourceCode cpp">format</code>? If we can, then at least this would be a pretty cheap operation. If we can’t, that in of itself might be a reason to eschew static delimiters. Note that <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code>’s implementation today does already store <code class="sourceCode cpp">string_view</code>s to the format specifier in order to handle named arguments (which are not yet standardized), which at least suggests that this is a safe thing to do - although this should probably be clarified in the <code class="sourceCode cpp">formatter</code> requirements regardless of whether we pursue static delimiters (since just because we don’t in this context, doesn’t mean that users won’t want to for their own types).</p>
<p>A more complete example from my own code base, where in some contexts we have a type like <code class="sourceCode cpp">span<span class="op">&lt;</span><span class="dt">unsigned</span> <span class="dt">char</span><span class="op">&gt;</span></code> we want to print in both hex and ascii. The three different levels of functionality there are:</p>
<blockquote>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1"></a><span class="co">// use fmt::join</span></span>
<span id="cb33-2"><a href="#cb33-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:#04x}: </span><span class="sc">\&quot;</span><span class="st">{}</span><span class="sc">\&quot;\n</span><span class="st">&quot;</span>,</span>
<span id="cb33-3"><a href="#cb33-3"></a>    fmt<span class="op">::</span>join<span class="op">(</span>data, <span class="st">&quot;,&quot;</span><span class="op">)</span>,</span>
<span id="cb33-4"><a href="#cb33-4"></a>    fmt<span class="op">::</span>join<span class="op">(</span>data <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="dt">unsigned</span> <span class="dt">char</span> c<span class="op">){</span></span>
<span id="cb33-5"><a href="#cb33-5"></a>        <span class="cf">return</span> std<span class="op">::</span>isprint<span class="op">(</span>c<span class="op">)</span> <span class="op">?</span> <span class="op">(</span><span class="dt">char</span><span class="op">)</span>c <span class="op">:</span> <span class="ch">&#39;.&#39;</span>;</span>
<span id="cb33-6"><a href="#cb33-6"></a>    <span class="op">})</span>, <span class="st">&quot;&quot;</span><span class="op">))</span>;</span>
<span id="cb33-7"><a href="#cb33-7"></a></span>
<span id="cb33-8"><a href="#cb33-8"></a><span class="co">// use dynamic delimiter</span></span>
<span id="cb33-9"><a href="#cb33-9"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:d{}:#04x} </span><span class="sc">\&quot;</span><span class="st">{:ed{}:}</span><span class="sc">\&quot;\n</span><span class="st">&quot;</span>,</span>
<span id="cb33-10"><a href="#cb33-10"></a>    data,</span>
<span id="cb33-11"><a href="#cb33-11"></a>    <span class="st">&quot;,&quot;</span>,</span>
<span id="cb33-12"><a href="#cb33-12"></a>    data <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="dt">unsigned</span> <span class="dt">char</span> c<span class="op">){</span></span>
<span id="cb33-13"><a href="#cb33-13"></a>        <span class="cf">return</span> std<span class="op">::</span>isprint<span class="op">(</span>c<span class="op">)</span> <span class="op">?</span> <span class="op">(</span><span class="dt">char</span><span class="op">)</span>c <span class="op">:</span> <span class="ch">&#39;.&#39;</span>;</span>
<span id="cb33-14"><a href="#cb33-14"></a>    <span class="op">})</span>,</span>
<span id="cb33-15"><a href="#cb33-15"></a>    <span class="st">&quot;&quot;</span><span class="op">)</span>;</span>
<span id="cb33-16"><a href="#cb33-16"></a></span>
<span id="cb33-17"><a href="#cb33-17"></a><span class="co">// use static delimiter</span></span>
<span id="cb33-18"><a href="#cb33-18"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:d[,]:#04x} </span><span class="sc">\&quot;</span><span class="st">{:ed[]:}</span><span class="sc">\&quot;\n</span><span class="st">&quot;</span>,</span>
<span id="cb33-19"><a href="#cb33-19"></a>    data,</span>
<span id="cb33-20"><a href="#cb33-20"></a>    data <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="dt">unsigned</span> <span class="dt">char</span> c<span class="op">){</span></span>
<span id="cb33-21"><a href="#cb33-21"></a>        <span class="cf">return</span> std<span class="op">::</span>isprint<span class="op">(</span>c<span class="op">)</span> <span class="op">?</span> <span class="op">(</span><span class="dt">char</span><span class="op">)</span>c <span class="op">:</span> <span class="ch">&#39;.&#39;</span>;</span>
<span id="cb33-22"><a href="#cb33-22"></a>    <span class="op">}))</span>;</span></code></pre></div>
</blockquote>
<p>Although with this particular example, this paper provides a better way to print the second part of this. We’re producing a range of <code class="sourceCode cpp"><span class="dt">char</span></code> and we want to print it with no delimiter and quoted. That’s <code class="sourceCode cpp"><span class="op">{:</span>s<span class="op">}</span></code>. So really the right way to present these levels are:</p>
<blockquote>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1"></a><span class="co">// use fmt::join</span></span>
<span id="cb34-2"><a href="#cb34-2"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:#04x}: {:s}</span><span class="sc">\n</span><span class="st">&quot;</span>,</span>
<span id="cb34-3"><a href="#cb34-3"></a>    fmt<span class="op">::</span>join<span class="op">(</span>data, <span class="st">&quot;,&quot;</span><span class="op">)</span>,</span>
<span id="cb34-4"><a href="#cb34-4"></a>    data <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="dt">unsigned</span> <span class="dt">char</span> c<span class="op">){</span></span>
<span id="cb34-5"><a href="#cb34-5"></a>        <span class="cf">return</span> std<span class="op">::</span>isprint<span class="op">(</span>c<span class="op">)</span> <span class="op">?</span> <span class="op">(</span><span class="dt">char</span><span class="op">)</span>c <span class="op">:</span> <span class="ch">&#39;.&#39;</span>;</span>
<span id="cb34-6"><a href="#cb34-6"></a>    <span class="op">}))</span>;</span>
<span id="cb34-7"><a href="#cb34-7"></a></span>
<span id="cb34-8"><a href="#cb34-8"></a><span class="co">// use dynamic delimiter</span></span>
<span id="cb34-9"><a href="#cb34-9"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:d{}:#04x} {:s}</span><span class="sc">\n</span><span class="st">&quot;</span>,</span>
<span id="cb34-10"><a href="#cb34-10"></a>    data,</span>
<span id="cb34-11"><a href="#cb34-11"></a>    <span class="st">&quot;,&quot;</span>,</span>
<span id="cb34-12"><a href="#cb34-12"></a>    data <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="dt">unsigned</span> <span class="dt">char</span> c<span class="op">){</span></span>
<span id="cb34-13"><a href="#cb34-13"></a>        <span class="cf">return</span> std<span class="op">::</span>isprint<span class="op">(</span>c<span class="op">)</span> <span class="op">?</span> <span class="op">(</span><span class="dt">char</span><span class="op">)</span>c <span class="op">:</span> <span class="ch">&#39;.&#39;</span>;</span>
<span id="cb34-14"><a href="#cb34-14"></a>    <span class="op">}))</span>;</span>
<span id="cb34-15"><a href="#cb34-15"></a></span>
<span id="cb34-16"><a href="#cb34-16"></a><span class="co">// use static delimiter</span></span>
<span id="cb34-17"><a href="#cb34-17"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:d[,]:#04x} {:s}</span><span class="sc">\n</span><span class="st">&quot;</span>,</span>
<span id="cb34-18"><a href="#cb34-18"></a>    data,</span>
<span id="cb34-19"><a href="#cb34-19"></a>    data <span class="op">|</span> views<span class="op">::</span>transform<span class="op">([](</span><span class="dt">unsigned</span> <span class="dt">char</span> c<span class="op">){</span></span>
<span id="cb34-20"><a href="#cb34-20"></a>        <span class="cf">return</span> std<span class="op">::</span>isprint<span class="op">(</span>c<span class="op">)</span> <span class="op">?</span> <span class="op">(</span><span class="dt">char</span><span class="op">)</span>c <span class="op">:</span> <span class="ch">&#39;.&#39;</span>;</span>
<span id="cb34-21"><a href="#cb34-21"></a>    <span class="op">}))</span>;</span></code></pre></div>
</blockquote>
<p>Static delimiter is limited by the fact that the delimiter must be static, so it cannot be the whole solution the problem. But it <em>is</em> a good solution to the common case where the delimiter is statically known. When it’s not (or based on user preference or other considerations), dynamic delimiter will be available as a fallback. Between these two options, that covers the complete set of functionality that <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> provides under <code class="sourceCode cpp">fmt<span class="op">::</span>join</code> (in fact, more than complete).</p>
<h4 data-number="3.3.7.5" id="pair-and-tuple-specifiers"><span class="header-section-number">3.3.7.5</span> Pair and Tuple Specifiers<a href="#pair-and-tuple-specifiers" class="self-link"></a></h4>
<p>This is the hard part.</p>
<p>To start with, we for consistency will support the same fill/align/width specifiers as usual.</p>
<p>For ranges, we can have the underlying element’s <code class="sourceCode cpp">formatter</code> simply parse the whole format specifier string from the character past the <code class="sourceCode cpp"><span class="op">:</span></code> to the <code class="sourceCode cpp"><span class="op">}</span></code>. The range doesn’t care anymore at that point, and what we’re left with is a specifier that the underlying element should understand (or not).</p>
<p>But for <code class="sourceCode cpp">pair</code>, it’s not so easy, because format strings can contain <em>anything</em>. Absolutely anything. So when trying to parse a format specifier for a <code class="sourceCode cpp">pair<span class="op">&lt;</span>X, Y<span class="op">&gt;</span></code>, how do you know where <code class="sourceCode cpp">X</code>’s format specifier ends and <code class="sourceCode cpp">Y</code>’s format specifier begins? This is, in general, impossible.</p>
<p>In <span class="citation" data-cites="P2286R3">[<a href="#ref-P2286R3" role="doc-biblioref">P2286R3</a>]</span>, this paper used Tim’s insight to take a page out of <code class="sourceCode cpp">sed</code>’s book and rely on the user providing the specifier string to actually know what they’re doing, and thus provide their own delimiter. <code class="sourceCode cpp">pair</code> will recognize the first character that is not one of its formatters as the delimiter, and then delimit based on that. This previous revision had proposed the following:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Format String</strong>
</div></th>
<th><div style="text-align:center">
<strong>Contents</strong>
</div></th>
<th><div style="text-align:center">
<strong>Formatted Output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">pair<span class="op">(</span><span class="dv">10</span>, <span class="dv">1729</span><span class="op">)</span></code></td>
<td><code class="x">(10, 1729)</code></td>
</tr>
<tr class="even">
<td><code class="x">{:}</code></td>
<td><code class="sourceCode cpp">pair<span class="op">(</span><span class="dv">10</span>, <span class="dv">1729</span><span class="op">)</span></code></td>
<td><code class="x">(10, 1729)</code></td>
</tr>
<tr class="odd">
<td><code class="x">{::#x:04X}</code></td>
<td><code class="sourceCode cpp">pair<span class="op">(</span><span class="dv">10</span>, <span class="dv">1729</span><span class="op">)</span></code></td>
<td><code class="x">(0xa, 06C1)</code></td>
</tr>
<tr class="even">
<td><code class="x">{:|#x|04X}</code></td>
<td><code class="sourceCode cpp">pair<span class="op">(</span><span class="dv">10</span>, <span class="dv">1729</span><span class="op">)</span></code></td>
<td><code class="x">(0xa, 06C1)</code></td>
</tr>
<tr class="odd">
<td><code class="x">{:Y#xY04X}</code></td>
<td><code class="sourceCode cpp">pair<span class="op">(</span><span class="dv">10</span>, <span class="dv">1729</span><span class="op">)</span></code></td>
<td><code class="x">(0xa, 06C1)</code></td>
</tr>
</tbody>
</table>
<p>The last three rows are equivalent, the difference is which character is used to delimit the specifiers: <code class="sourceCode cpp"><span class="op">:</span></code> or <code class="sourceCode cpp"><span class="op">|</span></code> or <code class="sourceCode cpp">Y</code>.</p>
<p>This approach, while technically functional, still leaves something to be desired. For one thing, these examples are already difficult to read and I haven’t even shown any additional nesting. We’re using to nested parentheses, brackets, or braces, but there’s nothing visually nested here. And it’s not even clear how to do something like that anyway. Several people expressed a desire to have a delimiter language that at least has some concept of nesting built-in - such as naturally-nesting punctuation like<code class="sourceCode cpp"><span class="op">()</span></code>s, <code class="sourceCode cpp"><span class="op">[]</span></code>s, or <code class="sourceCode cpp"><span class="op">{}</span>s</code> (Unicode has plenty of other pairs of open/close characters. I could revisit my Russian roots with <code class="sourceCode cpp">«</code> and <code class="sourceCode cpp">»</code>, or use something prettier like <code class="sourceCode cpp">⦕</code> and <code class="sourceCode cpp">⦖</code>).</p>
<p>The point, ultimately, is that it is difficult to comme up with a format specifier syntax that works <em>at all</em> in the presence of types that can use arbitrary characters in their specifiers. Like formatting <code class="sourceCode cpp">std<span class="op">::</span>chrono<span class="op">::</span>system_clock<span class="op">::</span>now<span class="op">()</span></code>:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Format String</strong>
</div></th>
<th><div style="text-align:center">
<strong>Formatted Output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp"><span class="op">{}</span></code></td>
<td><code class="x">2021-10-24 20:33:37</code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp"><span class="op">{:%</span>Y<span class="op">-%</span>m<span class="op">-%</span>d<span class="op">}</span></code></td>
<td><code class="x">2021-10-24</code></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp"><span class="op">{:%</span>H<span class="op">:%</span>M<span class="op">:%</span>S<span class="op">}</span></code></td>
<td><code class="x">20:33:37</code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp"><span class="op">{:%</span>H hours, <span class="op">%</span>M minutes, <span class="op">%</span>S seconds<span class="op">}</span></code></td>
<td><code class="x">20 hours, 33 minutes, 37 seconds</code></td>
</tr>
</tbody>
</table>
<p>Because there is reasonable concern about the complexity of the initially proposed solution, and because there doesn’t seem to be a lot of demand for actually being able to do this, in contrast to the very clear and present demand of being able to format pairs and tuples simply by default - this revision of this paper is withdrawing this part of the proposal in an effort to get the rest of the paper in for C++23.</p>
<p>To summarize: <code class="sourceCode cpp">std<span class="op">::</span>pair</code> and <code class="sourceCode cpp">std<span class="op">::</span>tuple</code> will only support:</p>
<ul>
<li>the fill/align/width specifiers from <em>std-format-spec</em></li>
<li>the <code class="sourceCode cpp"><span class="op">?</span></code> specifier, to format as debug (which is a no-op, since it will always format as debug, since there is no opt-out provided)</li>
<li>the <code class="sourceCode cpp">m</code> specifier, only valid for <code class="sourceCode cpp">pair</code> or 2-tuple, to format as <code class="sourceCode cpp">k<span class="op">:</span> v</code> instead of <code class="sourceCode cpp"><span class="op">(</span>k, v<span class="op">)</span></code></li>
</ul>
<p>It will additionally provide the function:</p>
<blockquote>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1"></a><span class="dt">void</span> set_debug_format<span class="op">()</span>;</span></code></pre></div>
</blockquote>
<p>and <code class="sourceCode cpp">pair</code> and <code class="sourceCode cpp">tuple</code> will provide the function:</p>
<blockquote>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1"></a><span class="dt">void</span> set_map_format<span class="op">()</span>;</span></code></pre></div>
</blockquote>
<p>which for <code class="sourceCode cpp">tuple</code> of size other than 2 will throw an exception (since you cannot format those as a map). To clarify the map specifier:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Format String</strong>
</div></th>
<th><div style="text-align:center">
<strong>Contents</strong>
</div></th>
<th><div style="text-align:center">
<strong>Formatted Output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp"><span class="op">{}</span></code></td>
<td><code class="sourceCode cpp">pair<span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">)</span></code></td>
<td><code class="sourceCode cpp"><span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">)</span></code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp"><span class="op">{:</span>m<span class="op">}</span></code></td>
<td><code class="sourceCode cpp">pair<span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">)</span></code></td>
<td><code class="sourceCode cpp"><span class="dv">1</span><span class="op">:</span> <span class="dv">2</span></code></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp"><span class="op">{:</span>m<span class="op">}</span></code></td>
<td><code class="sourceCode cpp">tuple<span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">)</span></code></td>
<td><code class="sourceCode cpp"><span class="dv">1</span><span class="op">:</span> <span class="dv">2</span></code></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp"><span class="op">{}</span></code></td>
<td><code class="sourceCode cpp">tuple<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code></td>
<td><code class="sourceCode cpp"><span class="op">(</span><span class="dv">1</span><span class="op">)</span></code></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp"><span class="op">{:</span>m<span class="op">}</span></code></td>
<td><code class="sourceCode cpp">tuple<span class="op">(</span><span class="dv">1</span><span class="op">)</span></code></td>
<td>exception or compile error</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp"><span class="op">{}</span></code></td>
<td><code class="sourceCode cpp">tuple<span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="st">&quot;3&quot;</span><span class="bu">s</span><span class="op">)</span></code></td>
<td><code class="sourceCode cpp"><span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="st">&quot;3&quot;</span><span class="op">)</span></code></td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp"><span class="op">{:</span>m<span class="op">}</span></code></td>
<td><code class="sourceCode cpp">tuple<span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="st">&quot;3&quot;</span><span class="bu">s</span><span class="op">)</span></code></td>
<td>exception or compile error</td>
</tr>
</tbody>
</table>
<h3 data-number="3.3.8" id="escaping-behavior"><span class="header-section-number">3.3.8</span> Escaping Behavior<a href="#escaping-behavior" class="self-link"></a></h3>
<p>Escaping of a string in a Unicode encoding is done by translating each UCS scalar value, or a code unit if it is not a part of a valid UCS scalar value, in sequence:</p>
<ul>
<li>If a UCS scalar value is one of <code class="sourceCode cpp"><span class="ch">&#39;</span><span class="sc">\t</span><span class="ch">&#39;</span></code>, <code class="sourceCode cpp"><span class="ch">&#39;</span><span class="sc">\r</span><span class="ch">&#39;</span></code>, <code class="sourceCode cpp"><span class="ch">&#39;</span><span class="sc">\n</span><span class="ch">&#39;</span></code>, <code class="sourceCode cpp"><span class="ch">&#39;</span><span class="sc">\\</span><span class="ch">&#39;</span></code> or <code class="sourceCode cpp"><span class="ch">&#39;&quot;&#39;</span></code>, it is replaced with <code class="sourceCode cpp"><span class="st">&quot;</span><span class="sc">\\</span><span class="st">t&quot;</span></code>, <code class="sourceCode cpp"><span class="st">&quot;</span><span class="sc">\\</span><span class="st">r&quot;</span></code>, <code class="sourceCode cpp"><span class="st">&quot;</span><span class="sc">\\</span><span class="st">n&quot;</span></code>, <code class="sourceCode cpp"><span class="st">&quot;</span><span class="sc">\\\\</span><span class="st">&quot;</span></code> and <code class="sourceCode cpp"><span class="st">&quot;</span><span class="sc">\\\&quot;</span><span class="st">&quot;</span></code> respectively.</li>
<li>Otherwise, if a UCS scalar value has a Unicode property Separator (Z) or Other (C), it is replaced with its universal character name escape sequence in the form <code class="sourceCode cpp"><span class="st">&quot;</span><span class="sc">\\</span><span class="st">u{<em>simple-hexadecimal-digit-sequence</em>}&quot;</span></code> as proposed by <span class="citation" data-cites="P2290R2">[<a href="#ref-P2290R2" role="doc-biblioref">P2290R2</a>]</span>, where <em>simple-hexadecimal-digit-sequence</em> is a hexadecimal representation of the UCS scalar value without leading zeros.</li>
<li>Otherwise, if a UCS scalar value has a Unicode property Grapheme_Extend and there are no UCS scalar values preceding it in the string without this property, it is replaced with its universal character name escape sequence as above.</li>
<li>Otherwise, a code unit that is not a part of a valid UCS scalar value is replaced with a hexadecimal escape sequence in the form <code class="sourceCode cpp"><span class="st">&quot;</span><span class="sc">\\</span><span class="st">x{<em>simple-hexadecimal-digit-sequence</em>}&quot;</span></code> as proposed by <span class="citation" data-cites="P2290R2">[<a href="#ref-P2290R2" role="doc-biblioref">P2290R2</a>]</span>, where <em>simple-hexadecimal-digit-sequence</em> is a hexadecimal representation of the code unit without leading zeros.</li>
<li>Otherwise, a UCS scalar value is copied as is.</li>
</ul>
<p>The same applies to wide strings with <code class="sourceCode cpp"><span class="ch">&#39;.</span><span class="er">..</span><span class="ch">&#39;</span></code> and <code class="sourceCode cpp"><span class="st">&quot;...&quot;</span></code> replaced with <code class="sourceCode cpp"><span class="ch">L&#39;.</span><span class="er">..</span><span class="ch">&#39;</span></code> and <code class="sourceCode cpp"><span class="st">L&quot;...&quot;</span></code> respectively.</p>
<p>For non-Unicode encodings an implementation-defined equivalent of Unicode properties is used.</p>
<p>Escape rules for characters are similar except that <code class="sourceCode cpp"><span class="ch">&#39;</span><span class="sc">\&#39;</span><span class="ch">&#39;</span></code> is escaped instead of <code class="sourceCode cpp"><span class="ch">&#39;&quot;&#39;</span></code> and <code class="sourceCode cpp"><span class="ch">&#39;&quot;&#39;</span></code> is not escaped.</p>
<p>Examples:</p>
<blockquote>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1"></a>std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:?}&quot;</span>, std<span class="op">::</span>string<span class="op">(</span><span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="op">))</span>;</span>
<span id="cb37-2"><a href="#cb37-2"></a><span class="co">// Output: &quot;h\tllo&quot;</span></span>
<span id="cb37-3"><a href="#cb37-3"></a></span>
<span id="cb37-4"><a href="#cb37-4"></a>std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:?}&quot;</span>, std<span class="op">::</span>string<span class="op">(</span><span class="st">&quot;</span><span class="sc">\0</span><span class="st"> </span><span class="sc">\n</span><span class="st"> </span><span class="sc">\t</span><span class="st"> </span><span class="sc">\x02</span><span class="st"> </span><span class="sc">\x1b</span><span class="st">&quot;</span>, <span class="dv">9</span><span class="op">))</span>;</span>
<span id="cb37-5"><a href="#cb37-5"></a><span class="co">// Output: &quot;\{0} \n \t \x{2} \x{1b}&quot;</span></span>
<span id="cb37-6"><a href="#cb37-6"></a></span>
<span id="cb37-7"><a href="#cb37-7"></a>std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:?}, {:?}, {:?}&quot;</span>, <span class="st">&quot; </span><span class="sc">\&quot;</span><span class="st"> &#39; &quot;</span>, <span class="ch">&#39;&quot;&#39;</span>, <span class="ch">&#39;</span><span class="sc">\&#39;</span><span class="ch">&#39;</span><span class="op">)</span>;</span>
<span id="cb37-8"><a href="#cb37-8"></a><span class="co">// Output: &quot; \&quot; &#39; &quot;, &#39;&quot;&#39;, &#39;\&#39;&#39;</span></span>
<span id="cb37-9"><a href="#cb37-9"></a></span>
<span id="cb37-10"><a href="#cb37-10"></a>std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:?}&quot;</span>, <span class="st">&quot;</span><span class="sc">\xc3\x28</span><span class="st">&quot;</span><span class="op">)</span>; <span class="co">// invalid UTF-8</span></span>
<span id="cb37-11"><a href="#cb37-11"></a><span class="co">// Output: &quot;\x{c3}\x{28}&quot;</span></span>
<span id="cb37-12"><a href="#cb37-12"></a></span>
<span id="cb37-13"><a href="#cb37-13"></a>std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:?}&quot;</span>, <span class="st">&quot;</span><span class="sc">\u0300</span><span class="st">&quot;</span><span class="op">)</span>; <span class="co">// assuming a Unicode encoding</span></span>
<span id="cb37-14"><a href="#cb37-14"></a><span class="co">// Output: &quot;\u{300}&quot;</span></span>
<span id="cb37-15"><a href="#cb37-15"></a><span class="co">// (as opposed to &quot;̀&quot; with an accent on the first &quot;)</span></span>
<span id="cb37-16"><a href="#cb37-16"></a></span>
<span id="cb37-17"><a href="#cb37-17"></a><span class="kw">auto</span> s <span class="op">=</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:?}&quot;</span>, <span class="st">&quot;Привет, 🕴️!&quot;</span><span class="op">)</span>; <span class="co">// assuming a Unicode encoding</span></span>
<span id="cb37-18"><a href="#cb37-18"></a><span class="co">// s == &quot;\&quot;Привет, 🕴️!\&quot;&quot;</span></span></code></pre></div>
</blockquote>
<p>Notes:</p>
<ul>
<li>SG16 requested using the escape sequence format proposed by <span class="citation" data-cites="P2290R2">[<a href="#ref-P2290R2" role="doc-biblioref">P2290R2</a>]</span>, <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> uses a non-braced escape format (same as Python).</li>
<li>Grapheme_Extend part is not implemented in <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> yet.</li>
</ul>
<h3 data-number="3.3.9" id="examples-with-user-defined-types"><span class="header-section-number">3.3.9</span> Examples with user-defined types<a href="#examples-with-user-defined-types" class="self-link"></a></h3>
<p>Let’s say a user has a type like:</p>
<blockquote>
<div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1"></a><span class="kw">struct</span> Foo <span class="op">{</span></span>
<span id="cb38-2"><a href="#cb38-2"></a>    <span class="dt">int</span> bar;</span>
<span id="cb38-3"><a href="#cb38-3"></a>    std<span class="op">::</span>string baz;</span>
<span id="cb38-4"><a href="#cb38-4"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>And want to format <code class="sourceCode cpp">Foo<span class="op">{.</span>bar<span class="op">=</span><span class="dv">10</span>, <span class="op">.</span>baz<span class="op">=</span><span class="st">&quot;Hello World&quot;</span><span class="op">}</span></code> as the string <code class="sourceCode cpp">Foo<span class="op">(</span>bar<span class="op">=</span><span class="dv">10</span>, baz<span class="op">=</span><span class="st">&quot;Hello World&quot;</span><span class="op">)</span></code>. They can do so this way:</p>
<blockquote>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span></span>
<span id="cb39-2"><a href="#cb39-2"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>Foo, <span class="dt">char</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb39-3"><a href="#cb39-3"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb39-4"><a href="#cb39-4"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> format<span class="op">(</span>Foo <span class="kw">const</span><span class="op">&amp;</span> f, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb39-5"><a href="#cb39-5"></a>        <span class="cf">return</span> format_to<span class="op">(</span>ctx<span class="op">.</span>out<span class="op">()</span>, <span class="st">&quot;Foo(bar={}, baz={:?})&quot;</span>, f<span class="op">.</span>bar, f<span class="op">.</span>baz<span class="op">)</span>;</span>
<span id="cb39-6"><a href="#cb39-6"></a>    <span class="op">}</span></span>
<span id="cb39-7"><a href="#cb39-7"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>How about wrappers?</p>
<p>Let’s say you have your own implementation of <code class="sourceCode cpp">Optional</code>, that you want to format the same way that Rust does: so that a disengaged one formats as <code class="sourceCode cpp">None</code> and an engaged one formats as <code class="sourceCode cpp">Some<span class="op">(??)</span></code>. We can start by:</p>
<blockquote>
<div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1"></a><span class="kw">template</span> <span class="op">&lt;</span>formattable<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;</span> T<span class="op">&gt;</span></span>
<span id="cb40-2"><a href="#cb40-2"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>Optional<span class="op">&lt;</span>T<span class="op">&gt;</span>, <span class="dt">char</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb40-3"><a href="#cb40-3"></a>    <span class="co">// we&#39;ll skip parse for now</span></span>
<span id="cb40-4"><a href="#cb40-4"></a></span>
<span id="cb40-5"><a href="#cb40-5"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb40-6"><a href="#cb40-6"></a>    <span class="kw">auto</span> format<span class="op">(</span>Optional<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span> opt, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-7"><a href="#cb40-7"></a>        <span class="cf">if</span> <span class="op">(</span><span class="kw">not</span> opt<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-8"><a href="#cb40-8"></a>            <span class="cf">return</span> format_to<span class="op">(</span>ctx<span class="op">.</span>out<span class="op">()</span>, <span class="st">&quot;None&quot;</span><span class="op">)</span>;</span>
<span id="cb40-9"><a href="#cb40-9"></a>        <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb40-10"><a href="#cb40-10"></a>            <span class="cf">return</span> format_to<span class="op">(</span>ctx<span class="op">.</span>out<span class="op">()</span>, <span class="st">&quot;Some({})&quot;</span>, <span class="op">*</span>opt<span class="op">)</span>;</span>
<span id="cb40-11"><a href="#cb40-11"></a>        <span class="op">}</span></span>
<span id="cb40-12"><a href="#cb40-12"></a>    <span class="op">}</span></span>
<span id="cb40-13"><a href="#cb40-13"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>If we had an <code class="sourceCode cpp">Optional<span class="op">&lt;</span>string<span class="op">&gt;(</span><span class="st">&quot;hello&quot;</span><span class="op">)</span></code>, this would format as <code class="sourceCode cpp">Some<span class="op">(</span>hello<span class="op">)</span></code>. Which may be fine. But what if we wanted to format it as <code class="sourceCode cpp">Some<span class="op">(</span><span class="st">&quot;hello&quot;</span><span class="op">)</span></code> instead? That is, take advantage of the quoting rules described earlier. What do you write instead of <code class="sourceCode cpp"><span class="op">*</span>opt</code> to format <code class="sourceCode cpp">string</code>s (or <code class="sourceCode cpp"><span class="dt">char</span></code>s or user-defined string-like types) as quoted in this context?</p>
<p>We can both add support for quoting/escaping and also arbitrary specifiers at the same time:</p>
<blockquote>
<div class="sourceCode" id="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-1"></a><span class="kw">template</span> <span class="op">&lt;</span>formattable<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;</span> T<span class="op">&gt;</span></span>
<span id="cb41-2"><a href="#cb41-2"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>Optional<span class="op">&lt;</span>T<span class="op">&gt;</span>, <span class="dt">char</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb41-3"><a href="#cb41-3"></a>    formatter<span class="op">&lt;</span>T, <span class="dt">char</span><span class="op">&gt;</span> underlying;</span>
<span id="cb41-4"><a href="#cb41-4"></a></span>
<span id="cb41-5"><a href="#cb41-5"></a>    <span class="kw">template</span> <span class="op">&lt;</span>typenaem ParseContext<span class="op">&gt;</span></span>
<span id="cb41-6"><a href="#cb41-6"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> parse<span class="op">(</span>ParseContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb41-7"><a href="#cb41-7"></a>        <span class="kw">auto</span> end <span class="op">=</span> underlying<span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb41-8"><a href="#cb41-8"></a>        <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">requires</span> <span class="op">{</span> underlying<span class="op">.</span>set_debug_format<span class="op">()</span>; <span class="op">})</span> <span class="op">{</span></span>
<span id="cb41-9"><a href="#cb41-9"></a>            underlying<span class="op">.</span>set_debug_format<span class="op">()</span>;</span>
<span id="cb41-10"><a href="#cb41-10"></a>        <span class="op">}</span></span>
<span id="cb41-11"><a href="#cb41-11"></a>        <span class="cf">return</span> end;</span>
<span id="cb41-12"><a href="#cb41-12"></a>    <span class="op">}</span></span>
<span id="cb41-13"><a href="#cb41-13"></a></span>
<span id="cb41-14"><a href="#cb41-14"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb41-15"><a href="#cb41-15"></a>    <span class="kw">auto</span> format<span class="op">(</span>Optional<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span> opt, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb41-16"><a href="#cb41-16"></a>        <span class="cf">if</span> <span class="op">(</span><span class="kw">not</span> opt<span class="op">)</span> <span class="op">{</span></span>
<span id="cb41-17"><a href="#cb41-17"></a>            <span class="cf">return</span> format_to<span class="op">(</span>ctx<span class="op">.</span>out<span class="op">()</span>, <span class="st">&quot;None&quot;</span><span class="op">)</span>;</span>
<span id="cb41-18"><a href="#cb41-18"></a>        <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb41-19"><a href="#cb41-19"></a>            ctx<span class="op">.</span>advance_to<span class="op">(</span>format_to<span class="op">(</span>ctx<span class="op">.</span>out<span class="op">()</span>, <span class="st">&quot;Some(&quot;</span><span class="op">))</span>;</span>
<span id="cb41-20"><a href="#cb41-20"></a>            <span class="kw">auto</span> out <span class="op">=</span> underlying<span class="op">.</span>format<span class="op">(*</span>opt, ctx<span class="op">)</span>;</span>
<span id="cb41-21"><a href="#cb41-21"></a>            <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;)&#39;</span>;</span>
<span id="cb41-22"><a href="#cb41-22"></a>            <span class="cf">return</span> out;</span>
<span id="cb41-23"><a href="#cb41-23"></a>        <span class="op">}</span></span>
<span id="cb41-24"><a href="#cb41-24"></a>    <span class="op">}</span></span>
<span id="cb41-25"><a href="#cb41-25"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>This lets me format <code class="sourceCode cpp">Optional<span class="op">&lt;</span>string<span class="op">&gt;(</span><span class="st">&quot;hello&quot;</span><span class="op">)</span></code> as <code class="x">Some(&quot;hello&quot;)</code> by default, or format <code class="sourceCode cpp">Optional<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;(</span><span class="dv">42</span><span class="op">)</span></code> as <code class="x">Some(0x2a)</code> if I provide the specifier string <code class="sourceCode cpp"><span class="st">&quot;{:#x}&quot;</span></code>.</p>
<h2 data-number="3.4" id="implementation-challenges"><span class="header-section-number">3.4</span> Implementation Challenges<a href="#implementation-challenges" class="self-link"></a></h2>
<p>I implemented the range and pair/tuple portions of this proposal on top of libfmt. I chose to do it on top so that I can easily share the implementation <span class="citation" data-cites="fmt-impl">[<a href="#ref-fmt-impl" role="doc-biblioref">fmt-impl</a>]</span>, as such I could not implement <code class="sourceCode cpp"><span class="op">?</span></code> support for strings and char, though that is not a very interesting part of this proposal (at least as far as implementability is concerned). There were two big issues that I ran into that are worth covering.</p>
<h3 data-number="3.4.1" id="wrapping-basic_format_context-is-not-generally-possible"><span class="header-section-number">3.4.1</span> Wrapping <code class="sourceCode cpp">basic_format_context</code> is not generally possible<a href="#wrapping-basic_format_context-is-not-generally-possible" class="self-link"></a></h3>
<p>In order to be able to provide an arbitrary type’s specifiers to format a range, you have to have a <code class="sourceCode cpp">formatter<span class="op">&lt;</span>V<span class="op">&gt;</span></code> for the underlying type and use that specific <code class="sourceCode cpp">formatter</code> in order to <code class="sourceCode cpp">parse</code> the format specifier and then <code class="sourceCode cpp">format</code> into the given context. If that’s all you’re doing, this isn’t that big a deal, and I showed a simplified implementation of <code class="sourceCode cpp">range_formatter<span class="op">&lt;</span>V<span class="op">&gt;</span></code> <a href="#the-debug-specifier">earlier</a>.</p>
<p>However, if you additionally want to support fill/pad/align, then the game changes. You can’t format into the provided context - you have to format into <em>something else</em> first and then do the adjustments later. Adding padding support ends up doing something more like this:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>No padding</strong>
</div></th>
<th><div style="text-align:center">
<strong>With padding</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb42"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb42-1"><a href="#cb42-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R, <span class="kw">typename</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb42-2"><a href="#cb42-2"></a><span class="kw">constexpr</span> <span class="kw">auto</span> format<span class="op">(</span>R<span class="op">&amp;&amp;</span> r, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb42-3"><a href="#cb42-3"></a>    <span class="kw">auto</span> out <span class="op">=</span> ctx<span class="op">.</span>out<span class="op">()</span>;</span>
<span id="cb42-4"><a href="#cb42-4"></a>    <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;[&#39;</span>;</span>
<span id="cb42-5"><a href="#cb42-5"></a>    <span class="kw">auto</span> first <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb42-6"><a href="#cb42-6"></a>    <span class="kw">auto</span> last <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>end<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb42-7"><a href="#cb42-7"></a>    <span class="cf">if</span> <span class="op">(</span>first <span class="op">!=</span> last<span class="op">)</span> <span class="op">{</span></span>
<span id="cb42-8"><a href="#cb42-8"></a>        ctx<span class="op">.</span>advance_to<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>out<span class="op">))</span>;</span>
<span id="cb42-9"><a href="#cb42-9"></a>        out <span class="op">=</span> underlying<span class="op">.</span>format<span class="op">(*</span>first, ctx<span class="op">)</span>;</span>
<span id="cb42-10"><a href="#cb42-10"></a>        <span class="cf">for</span> <span class="op">(++</span>first; first <span class="op">!=</span> last; <span class="op">++</span>first<span class="op">)</span> <span class="op">{</span></span>
<span id="cb42-11"><a href="#cb42-11"></a>            <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;,&#39;</span>;</span>
<span id="cb42-12"><a href="#cb42-12"></a>            <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39; &#39;</span>;</span>
<span id="cb42-13"><a href="#cb42-13"></a>            ctx<span class="op">.</span>advance_to<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>out<span class="op">))</span>;</span>
<span id="cb42-14"><a href="#cb42-14"></a>            out <span class="op">=</span> underlying<span class="op">.</span>format<span class="op">(*</span>first, ctx<span class="op">)</span>;</span>
<span id="cb42-15"><a href="#cb42-15"></a>        <span class="op">}</span></span>
<span id="cb42-16"><a href="#cb42-16"></a>    <span class="op">}</span></span>
<span id="cb42-17"><a href="#cb42-17"></a>    <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;]&#39;</span>;</span>
<span id="cb42-18"><a href="#cb42-18"></a>    <span class="cf">return</span> out;</span>
<span id="cb42-19"><a href="#cb42-19"></a><span class="op">}</span></span></code></pre></div></td>
<td><div class="sourceCode" id="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R, <span class="kw">typename</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb43-2"><a href="#cb43-2"></a><span class="kw">constexpr</span> <span class="kw">auto</span> format<span class="op">(</span>R<span class="op">&amp;&amp;</span> r, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb43-3"><a href="#cb43-3"></a>    <span class="co">// fmt has a dynamically growing buffer: memory_buffer</span></span>
<span id="cb43-4"><a href="#cb43-4"></a>    <span class="co">// and a type-erased iterator into it: appender</span></span>
<span id="cb43-5"><a href="#cb43-5"></a>    fmt<span class="op">::</span>memory_buffer buf;</span>
<span id="cb43-6"><a href="#cb43-6"></a>    fmt<span class="op">::</span>basic_format_context<span class="op">&lt;</span>fmt<span class="op">::</span>appender, <span class="dt">char</span><span class="op">&gt;</span></span>
<span id="cb43-7"><a href="#cb43-7"></a>      bctx<span class="op">(</span>fmt<span class="op">::</span>appender<span class="op">(</span>buf<span class="op">)</span>, ctx<span class="op">.</span>args<span class="op">()</span>, ctx<span class="op">.</span>locale<span class="op">())</span>;</span>
<span id="cb43-8"><a href="#cb43-8"></a></span>
<span id="cb43-9"><a href="#cb43-9"></a>    <span class="kw">auto</span> out <span class="op">=</span> bctx<span class="op">.</span>out<span class="op">()</span>;</span>
<span id="cb43-10"><a href="#cb43-10"></a>    <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;[&#39;</span>;</span>
<span id="cb43-11"><a href="#cb43-11"></a>    <span class="kw">auto</span> first <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb43-12"><a href="#cb43-12"></a>    <span class="kw">auto</span> last <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>end<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb43-13"><a href="#cb43-13"></a>    <span class="cf">if</span> <span class="op">(</span>first <span class="op">!=</span> last<span class="op">)</span> <span class="op">{</span></span>
<span id="cb43-14"><a href="#cb43-14"></a>        bctx<span class="op">.</span>advance_to<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>out<span class="op">))</span>;</span>
<span id="cb43-15"><a href="#cb43-15"></a>        out <span class="op">=</span> underlying<span class="op">.</span>format<span class="op">(*</span>first, bctx<span class="op">)</span>;</span>
<span id="cb43-16"><a href="#cb43-16"></a>        <span class="cf">for</span> <span class="op">(++</span>first; first <span class="op">!=</span> last; <span class="op">++</span>first<span class="op">)</span> <span class="op">{</span></span>
<span id="cb43-17"><a href="#cb43-17"></a>            <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;,&#39;</span>;</span>
<span id="cb43-18"><a href="#cb43-18"></a>            <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39; &#39;</span>;</span>
<span id="cb43-19"><a href="#cb43-19"></a>            bctx<span class="op">.</span>advance_to<span class="op">(</span>std<span class="op">::</span>move<span class="op">(</span>out<span class="op">))</span>;</span>
<span id="cb43-20"><a href="#cb43-20"></a>            out <span class="op">=</span> underlying<span class="op">.</span>format<span class="op">(*</span>first, bctx<span class="op">)</span>;</span>
<span id="cb43-21"><a href="#cb43-21"></a>        <span class="op">}</span></span>
<span id="cb43-22"><a href="#cb43-22"></a>    <span class="op">}</span></span>
<span id="cb43-23"><a href="#cb43-23"></a>    <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;]&#39;</span>;</span>
<span id="cb43-24"><a href="#cb43-24"></a></span>
<span id="cb43-25"><a href="#cb43-25"></a>    <span class="co">// at this point, we formatted our range into buf, so</span></span>
<span id="cb43-26"><a href="#cb43-26"></a>    <span class="co">// now we need to format buf into the *real* context,</span></span>
<span id="cb43-27"><a href="#cb43-27"></a>    <span class="co">// ctx.out(), with fill/pad/align. That part isn&#39;t</span></span>
<span id="cb43-28"><a href="#cb43-28"></a>    <span class="co">// interesting for our purposes here</span></span>
<span id="cb43-29"><a href="#cb43-29"></a>    <span class="cf">return</span> <em>write-padded-aligned</em><span class="op">(</span>ctx<span class="op">.</span>out<span class="op">()</span>, buf<span class="op">)</span>;</span>
<span id="cb43-30"><a href="#cb43-30"></a><span class="op">}</span></span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>It’s mostly the same - we format into <code class="sourceCode cpp">bctx</code> instead of <code class="sourceCode cpp">ctx</code> and then <code class="sourceCode cpp">write</code> into <code class="sourceCode cpp">ctx</code> later using the <code class="sourceCode cpp">specs</code> that we already parsed. The code seems straightforward enough, except…</p>
<p>First, we don’t even expose a way to construct <code class="sourceCode cpp">basic_format_context</code> so can’t do this at all (there’s no specified constructor for it in <span>20.20.6.4 <a href="https://wg21.link/format.context">[format.context]</a></span>). Nor do we expose a way of constructing an iterator type for formatting into some buffer. And if we could construct these things, the real problem hits when we try to construct this new context. We need some kind of <code class="sourceCode cpp">fmt<span class="op">::</span>basic_format_context<span class="op">&lt;???</span>, <span class="dt">char</span><span class="op">&gt;</span></code>, and we need to write into some kind of dynamic buffer, so <code class="sourceCode cpp">fmt<span class="op">::</span>appender</code> is the appropriate choice for iterator. But the issue here is that <code class="sourceCode cpp">fmt<span class="op">::</span>basic_format_context<span class="op">&lt;</span>Out, CharT<span class="op">&gt;</span></code> has a member <code class="sourceCode cpp">fmt<span class="op">::</span>basic_format_args<span class="op">&lt;</span>basic_format_context<span class="op">&gt;</span></code> - the underlying arguments are templates <em>on the context</em>. We can’t just… change the <code class="sourceCode cpp">basic_format_args</code> to have a different context, this is a fairly fundamental attachment in the design.</p>
<p>The <em>only</em> type for the output iterator that I can support in this implementation is precisely <code class="sourceCode cpp">fmt<span class="op">::</span>appender</code>.</p>
<p>This seems like it’d be <em>extremely</em> limiting.</p>
<p>Except it turns out that <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> uses exactly this iterator in a whole lot of places. <code class="sourceCode cpp">fmt<span class="op">::</span>print</code>, <code class="sourceCode cpp">fmt<span class="op">::</span>format</code>, <code class="sourceCode cpp">fmt<span class="op">::</span>format_to</code>, <code class="sourceCode cpp">fmt<span class="op">::</span>format_to_n</code>, <code class="sourceCode cpp">fmt<span class="op">::</span>vformat</code>, etc., all only use this one iterator type. This is because of <span class="citation" data-cites="P2216R3">[<a href="#ref-P2216R3" role="doc-biblioref">P2216R3</a>]</span>’s efforts to reduce code bloat by type erasing the output iterator.</p>
<p>However, there is one part of <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> that uses a different iterator type, which the above implementation fails on:</p>
<blockquote>
<div class="sourceCode" id="cb44"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb44-1"><a href="#cb44-1"></a>fmt<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:::d}&quot;</span>, vector<span class="op">{</span>vector<span class="op">{</span><span class="ch">&#39;a&#39;</span><span class="op">}</span>, vector<span class="op">{</span><span class="ch">&#39;b&#39;</span>, <span class="ch">&#39;c&#39;</span><span class="op">}})</span>;              <span class="co">// ok: [[97], [98, 99]]</span></span>
<span id="cb44-2"><a href="#cb44-2"></a>fmt<span class="op">::</span>format<span class="op">(</span>FMT_COMPILE<span class="op">(</span><span class="st">&quot;{:::d}&quot;</span><span class="op">)</span>, vector<span class="op">{</span>vector<span class="op">{</span><span class="ch">&#39;a&#39;</span><span class="op">}</span>, vector<span class="op">{</span><span class="ch">&#39;b&#39;</span>, <span class="ch">&#39;c&#39;</span><span class="op">}})</span>; <span class="co">// ill-formed</span></span></code></pre></div>
</blockquote>
<p>The latter fails because there the initial output iterator type is <code class="sourceCode cpp">std<span class="op">::</span>back_insert_iterator<span class="op">&lt;</span>std<span class="op">::</span>string<span class="op">&gt;</span></code>. This is a different iterator type from <code class="sourceCode cpp">fmt<span class="op">::</span>appender</code>, so we get a mismatch in the types of the <code class="sourceCode cpp">basic_format_args</code> specializations, and cannot compile the construction of <code class="sourceCode cpp">bctx</code>.</p>
<p>This can be worked around (I just need to know what the type of the buffer needs to be, in the usual case it’s <code class="sourceCode cpp">fmt<span class="op">::</span>memory_buffer</code> and here it becomes <code class="sourceCode cpp">std<span class="op">::</span>string</code>, that’s fine), but it means we really need to nail down what the requirements of the <code class="sourceCode cpp">formatter</code> API are. One of the things we need to do in this paper is provide a <code class="sourceCode cpp">formattable</code> concept. From a previous revision of that paper, dropping the <code class="sourceCode cpp"><span class="dt">char</span></code> parameter for simplicity, that looks like:</p>
<blockquote>
<div class="sourceCode" id="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb45-2"><a href="#cb45-2"></a><span class="kw">concept</span> <em>formattable-impl</em> <span class="op">=</span></span>
<span id="cb45-3"><a href="#cb45-3"></a>    std<span class="op">::</span>semiregular<span class="op">&lt;</span>fmt<span class="op">::</span>formatter<span class="op">&lt;</span>T<span class="op">&gt;&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb45-4"><a href="#cb45-4"></a>    <span class="kw">requires</span> <span class="op">(</span>fmt<span class="op">::</span>formatter<span class="op">&lt;</span>T<span class="op">&gt;</span> f,</span>
<span id="cb45-5"><a href="#cb45-5"></a>              <span class="kw">const</span> T t,</span>
<span id="cb45-6"><a href="#cb45-6"></a>              fmt<span class="op">::</span>basic_format_context<span class="op">&lt;</span><span class="dt">char</span><span class="op">*</span>, <span class="dt">char</span><span class="op">&gt;</span> fc,</span>
<span id="cb45-7"><a href="#cb45-7"></a>              fmt<span class="op">::</span>basic_format_parse_context<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;</span> pc<span class="op">)</span></span>
<span id="cb45-8"><a href="#cb45-8"></a>    <span class="op">{</span></span>
<span id="cb45-9"><a href="#cb45-9"></a>        <span class="op">{</span> f<span class="op">.</span>parse<span class="op">(</span>pc<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>same_as<span class="op">&lt;</span>fmt<span class="op">::</span>basic_format_parse_context<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;::</span>iterator<span class="op">&gt;</span>;</span>
<span id="cb45-10"><a href="#cb45-10"></a>        <span class="op">{</span> f<span class="op">.</span>format<span class="op">(</span>t, fc<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>same_as<span class="op">&lt;</span><span class="dt">char</span><span class="op">*&gt;</span>;</span>
<span id="cb45-11"><a href="#cb45-11"></a>    <span class="op">}</span>;</span>
<span id="cb45-12"><a href="#cb45-12"></a></span>
<span id="cb45-13"><a href="#cb45-13"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb45-14"><a href="#cb45-14"></a><span class="kw">concept</span> formattable <span class="op">=</span> <em>formattable-impl</em><span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>T<span class="op">&gt;&gt;</span>;</span></code></pre></div>
</blockquote>
<p>Note that based on the resolution of <span class="citation" data-cites="LWG3636">[<a href="#ref-LWG3636" role="doc-biblioref">LWG3636</a>]</span>, the call to <code class="sourceCode cpp">format</code> may be on a <code class="sourceCode cpp"><span class="kw">const</span> fmt<span class="op">::</span>formatter<span class="op">&lt;</span>T<span class="op">&gt;</span></code> instead.</p>
<p>I use <code class="sourceCode cpp"><span class="dt">char</span><span class="op">*</span></code> as the output iterator, but my <code class="sourceCode cpp">range_formatter<span class="op">&lt;</span>V<span class="op">&gt;</span></code> cannot support <code class="sourceCode cpp"><span class="dt">char</span><span class="op">*</span></code> as an output iterator type at all. Do <code class="sourceCode cpp">formatter</code> specializations need to support any output iterator type? If so, how can we implement fill/align/pad support in <code class="sourceCode cpp">range_formatter</code>?</p>
<p>The simplest approach would be to state that there actually is only one output iterator type that need be support per character type. But this would prohibit the approach <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> uses to process the format string at compile time, as well as any potential future optimizations. This just seems like a non-starter.</p>
<p>A different approach would be to introduce a new API that allows the implementation to produce a new context for us. That approach could look like this:</p>
<blockquote>
<div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> V, <span class="kw">typename</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb46-2"><a href="#cb46-2"></a><span class="kw">constexpr</span> <span class="kw">auto</span> format<span class="op">(</span>V<span class="op">&amp;&amp;</span> value, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">typename</span> FormatContext<span class="op">::</span>iterator</span>
<span id="cb46-3"><a href="#cb46-3"></a><span class="op">{</span></span>
<span id="cb46-4"><a href="#cb46-4"></a>    <span class="co">// ctx here is a basic_format_context&lt;OutIt, CharT&gt;, for some output iterator</span></span>
<span id="cb46-5"><a href="#cb46-5"></a>    <span class="co">// and some character type</span></span>
<span id="cb46-6"><a href="#cb46-6"></a></span>
<span id="cb46-7"><a href="#cb46-7"></a>    <span class="co">// can use a vector&lt;CharT&gt;, basic_string&lt;CharT&gt;, or some custom buffer like</span></span>
<span id="cb46-8"><a href="#cb46-8"></a>    <span class="co">// fmt::buffer, user&#39;s choice</span></span>
<span id="cb46-9"><a href="#cb46-9"></a>    vector<span class="op">&lt;</span>CharT<span class="op">&gt;</span> buf;</span>
<span id="cb46-10"><a href="#cb46-10"></a></span>
<span id="cb46-11"><a href="#cb46-11"></a>    <span class="co">// The job of the retargeted_format_context class template is to produce</span></span>
<span id="cb46-12"><a href="#cb46-12"></a>    <span class="co">// a new specialization of basic_format_context for the provided iterator</span></span>
<span id="cb46-13"><a href="#cb46-13"></a>    <span class="co">// that simply does The Right Thing (TM).</span></span>
<span id="cb46-14"><a href="#cb46-14"></a>    <span class="co">// We do not need bctx here to be specifically (w)format_context, just some</span></span>
<span id="cb46-15"><a href="#cb46-15"></a>    <span class="co">// specialization of basic_format_context that is definitely going to write</span></span>
<span id="cb46-16"><a href="#cb46-16"></a>    <span class="co">// into buf (regardless of buf&#39;s type).</span></span>
<span id="cb46-17"><a href="#cb46-17"></a>    retargeted_format_context rctx<span class="op">(</span>ctx, std<span class="op">::</span>back_inserter<span class="op">(</span>buf<span class="op">))</span>;</span>
<span id="cb46-18"><a href="#cb46-18"></a>    <span class="kw">auto</span><span class="op">&amp;</span> bctx <span class="op">=</span> rctx<span class="op">.</span>context<span class="op">()</span>;</span>
<span id="cb46-19"><a href="#cb46-19"></a></span>
<span id="cb46-20"><a href="#cb46-20"></a>    <span class="co">// format into bctx...</span></span>
<span id="cb46-21"><a href="#cb46-21"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>There is one fundamental limitation here that is sort of inherent in the design. If the user-defined types want to reference some other argument (i.e. something like dynamic width or dynamic precision) but want that other argument to <em>also</em> be a user-defined type (rather than just an integer or <code class="sourceCode cpp">string_view</code>/<code class="sourceCode cpp"><span class="dt">char</span> <span class="kw">const</span><span class="op">*</span></code>), they basically cannot. Thta’s not an option. User-defined types are type erased as <code class="sourceCode cpp">handle</code> (see <span>20.20.7.1 <a href="https://wg21.link/format.arg">[format.arg]</a></span>), and <code class="sourceCode cpp">handle</code> can only be formatted with a <code class="sourceCode cpp"><span class="op">(</span>w<span class="op">)</span>format_parse_context</code> - which only the implementation would have access to.</p>
<p>However, if we ignore user-defined types entirely, it is straightforward to convert all the other <code class="sourceCode cpp">format_arg</code>s from one context to another, since we know everything about all of those types and they are all cheap to copy.</p>
<p>The implementation approach I used is as follows:</p>
<blockquote>
<div class="sourceCode" id="cb47"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb47-1"><a href="#cb47-1"></a><span class="co">// effectively a tagged version of fmt::appender, solely for</span></span>
<span id="cb47-2"><a href="#cb47-2"></a><span class="co">// specializing on top of</span></span>
<span id="cb47-3"><a href="#cb47-3"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Old<span class="op">&gt;</span></span>
<span id="cb47-4"><a href="#cb47-4"></a><span class="kw">struct</span> custom_appender <span class="op">:</span> appender <span class="op">{</span></span>
<span id="cb47-5"><a href="#cb47-5"></a>    <span class="kw">using</span> appender<span class="op">::</span>appender;</span>
<span id="cb47-6"><a href="#cb47-6"></a><span class="op">}</span>;</span>
<span id="cb47-7"><a href="#cb47-7"></a></span>
<span id="cb47-8"><a href="#cb47-8"></a><span class="co">// specialization of basic_format_args for use with custom_appender</span></span>
<span id="cb47-9"><a href="#cb47-9"></a><span class="co">// This ended up being easier than specializing basic_format_context.</span></span>
<span id="cb47-10"><a href="#cb47-10"></a><span class="co">// This specialization is only used in the context of retargeted_format_context.</span></span>
<span id="cb47-11"><a href="#cb47-11"></a><span class="co">//</span></span>
<span id="cb47-12"><a href="#cb47-12"></a><span class="co">// Note that here we hold a reference to the original basic_format_args: we don&#39;t</span></span>
<span id="cb47-13"><a href="#cb47-13"></a><span class="co">// have to make a copy, and we only produce a new basic_format_arg if actually</span></span>
<span id="cb47-14"><a href="#cb47-14"></a><span class="co">// requiried by the formatting. This means we don&#39;t have to pay for anything that</span></span>
<span id="cb47-15"><a href="#cb47-15"></a><span class="co">// we don&#39;t use</span></span>
<span id="cb47-16"><a href="#cb47-16"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Old<span class="op">&gt;</span></span>
<span id="cb47-17"><a href="#cb47-17"></a><span class="kw">struct</span> basic_format_args<span class="op">&lt;</span>basic_format_context<span class="op">&lt;</span>custom_appender<span class="op">&lt;</span>Old<span class="op">&gt;</span>, <span class="dt">char</span><span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb47-18"><a href="#cb47-18"></a>    <span class="kw">using</span> old_args <span class="op">=</span> basic_format_args<span class="op">&lt;</span>basic_format_context<span class="op">&lt;</span>Old, <span class="dt">char</span><span class="op">&gt;&gt;</span>;</span>
<span id="cb47-19"><a href="#cb47-19"></a>    <span class="kw">using</span> new_context <span class="op">=</span> basic_format_context<span class="op">&lt;</span>custom_appender<span class="op">&lt;</span>Old<span class="op">&gt;</span>, <span class="dt">char</span><span class="op">&gt;</span>;</span>
<span id="cb47-20"><a href="#cb47-20"></a>    <span class="kw">using</span> format_arg <span class="op">=</span> basic_format_arg<span class="op">&lt;</span>new_context<span class="op">&gt;</span>;</span>
<span id="cb47-21"><a href="#cb47-21"></a>    <span class="kw">using</span> size_type <span class="op">=</span> <span class="dt">int</span>;</span>
<span id="cb47-22"><a href="#cb47-22"></a></span>
<span id="cb47-23"><a href="#cb47-23"></a>    old_args <span class="kw">const</span><span class="op">&amp;</span> orig_args;</span>
<span id="cb47-24"><a href="#cb47-24"></a></span>
<span id="cb47-25"><a href="#cb47-25"></a>    basic_format_args<span class="op">(</span>old_args <span class="kw">const</span><span class="op">&amp;</span> orig<span class="op">)</span></span>
<span id="cb47-26"><a href="#cb47-26"></a>        <span class="op">:</span> orig_args<span class="op">(</span>orig<span class="op">)</span></span>
<span id="cb47-27"><a href="#cb47-27"></a>    <span class="op">{</span> <span class="op">}</span></span>
<span id="cb47-28"><a href="#cb47-28"></a></span>
<span id="cb47-29"><a href="#cb47-29"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> get<span class="op">(</span><span class="dt">int</span> id<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> format_arg <span class="op">{</span></span>
<span id="cb47-30"><a href="#cb47-30"></a>        <span class="cf">return</span> visit_format_arg<span class="op">([]&lt;</span><span class="kw">typename</span> T<span class="op">&gt;(</span>T <span class="kw">const</span><span class="op">&amp;</span> arg<span class="op">)</span> <span class="op">-&gt;</span> format_arg <span class="op">{</span></span>
<span id="cb47-31"><a href="#cb47-31"></a>            <span class="co">// User-defined types or out-of-range arguments can&#39;t produce any</span></span>
<span id="cb47-32"><a href="#cb47-32"></a>            <span class="co">// valid format_arg, so we return no format_arg</span></span>
<span id="cb47-33"><a href="#cb47-33"></a>            <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>std<span class="op">::</span>same_as<span class="op">&lt;</span>T, <span class="kw">typename</span> old_args<span class="op">::</span>format_arg<span class="op">::</span>handle<span class="op">&gt;</span></span>
<span id="cb47-34"><a href="#cb47-34"></a>                        <span class="kw">or</span> std<span class="op">::</span>same_as<span class="op">&lt;</span>T, monostate<span class="op">&gt;)</span> <span class="op">{</span></span>
<span id="cb47-35"><a href="#cb47-35"></a>                <span class="cf">return</span> format_arg<span class="op">()</span>;</span>
<span id="cb47-36"><a href="#cb47-36"></a>            <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb47-37"><a href="#cb47-37"></a>                <span class="co">// ... but for all the other types, this is a cheap copy</span></span>
<span id="cb47-38"><a href="#cb47-38"></a>                <span class="co">// T is bool, char, some integral type, some floating point</span></span>
<span id="cb47-39"><a href="#cb47-39"></a>                <span class="co">// type, char const*, string_view, or void const*</span></span>
<span id="cb47-40"><a href="#cb47-40"></a>                <span class="cf">return</span> detail<span class="op">::</span>make_arg<span class="op">&lt;</span>new_context<span class="op">&gt;(</span>arg<span class="op">)</span>;</span>
<span id="cb47-41"><a href="#cb47-41"></a>            <span class="op">}</span></span>
<span id="cb47-42"><a href="#cb47-42"></a>        <span class="op">}</span>, orig_args<span class="op">.</span>get<span class="op">(</span>id<span class="op">))</span>;</span>
<span id="cb47-43"><a href="#cb47-43"></a>    <span class="op">}</span></span>
<span id="cb47-44"><a href="#cb47-44"></a></span>
<span id="cb47-45"><a href="#cb47-45"></a>    <span class="co">// These next two functions are {fmt}-specific, since std:: doesn&#39;t</span></span>
<span id="cb47-46"><a href="#cb47-46"></a>    <span class="co">// have argument names. But if it did, as you can see, these calls are</span></span>
<span id="cb47-47"><a href="#cb47-47"></a>    <span class="co">// pretty straightforward</span></span>
<span id="cb47-48"><a href="#cb47-48"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> get<span class="op">(</span>fmt<span class="op">::</span>string_view name<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> format_arg <span class="op">{</span></span>
<span id="cb47-49"><a href="#cb47-49"></a>        <span class="dt">int</span> id <span class="op">=</span> orig_args<span class="op">.</span>get_id<span class="op">(</span>name<span class="op">)</span>;</span>
<span id="cb47-50"><a href="#cb47-50"></a>        <span class="cf">return</span> id <span class="op">&gt;=</span> <span class="dv">0</span> <span class="op">?</span> get<span class="op">(</span>id<span class="op">)</span> <span class="op">:</span> format_arg<span class="op">()</span>;</span>
<span id="cb47-51"><a href="#cb47-51"></a>    <span class="op">}</span></span>
<span id="cb47-52"><a href="#cb47-52"></a></span>
<span id="cb47-53"><a href="#cb47-53"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> get_id<span class="op">(</span>fmt<span class="op">::</span>string_view name<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <span class="dt">int</span> <span class="op">{</span></span>
<span id="cb47-54"><a href="#cb47-54"></a>        <span class="cf">return</span> orig_args<span class="op">.</span>get_id<span class="op">(</span>name<span class="op">)</span>;</span>
<span id="cb47-55"><a href="#cb47-55"></a>    <span class="op">}</span></span>
<span id="cb47-56"><a href="#cb47-56"></a><span class="op">}</span>;</span>
<span id="cb47-57"><a href="#cb47-57"></a></span>
<span id="cb47-58"><a href="#cb47-58"></a><span class="co">// In the case where we do need to retarget, we build a new context using</span></span>
<span id="cb47-59"><a href="#cb47-59"></a><span class="co">// custom_appender&lt;Context::iterator&gt;, which will use the specialization of</span></span>
<span id="cb47-60"><a href="#cb47-60"></a><span class="co">// basic_format_args defined above (no new basic_format_args are created)</span></span>
<span id="cb47-61"><a href="#cb47-61"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Context, <span class="kw">typename</span> OutputIt<span class="op">&gt;</span></span>
<span id="cb47-62"><a href="#cb47-62"></a><span class="kw">struct</span> retargeted_format_context <span class="op">{</span></span>
<span id="cb47-63"><a href="#cb47-63"></a>    detail<span class="op">::</span>iterator_buffer<span class="op">&lt;</span>OutputIt, <span class="dt">char</span><span class="op">&gt;</span> buffer;</span>
<span id="cb47-64"><a href="#cb47-64"></a></span>
<span id="cb47-65"><a href="#cb47-65"></a>    <span class="kw">using</span> iterator <span class="op">=</span> custom_appender<span class="op">&lt;</span><span class="kw">typename</span> Context<span class="op">::</span>iterator<span class="op">&gt;</span>;</span>
<span id="cb47-66"><a href="#cb47-66"></a>    <span class="kw">using</span> new_context <span class="op">=</span> basic_format_context<span class="op">&lt;</span>iterator, <span class="dt">char</span><span class="op">&gt;</span>;</span>
<span id="cb47-67"><a href="#cb47-67"></a>    new_context erased_ctx;</span>
<span id="cb47-68"><a href="#cb47-68"></a></span>
<span id="cb47-69"><a href="#cb47-69"></a>    retargeted_format_context<span class="op">(</span>Context<span class="op">&amp;</span> ctx, OutputIt it<span class="op">)</span></span>
<span id="cb47-70"><a href="#cb47-70"></a>        <span class="op">:</span> buffer<span class="op">(</span>it<span class="op">)</span></span>
<span id="cb47-71"><a href="#cb47-71"></a>        , erased_ctx<span class="op">(</span>iterator<span class="op">(</span>buffer<span class="op">)</span>,</span>
<span id="cb47-72"><a href="#cb47-72"></a>                        basic_format_args<span class="op">&lt;</span>new_context<span class="op">&gt;(</span>ctx<span class="op">.</span>args<span class="op">())</span>,</span>
<span id="cb47-73"><a href="#cb47-73"></a>                        ctx<span class="op">.</span>locale<span class="op">())</span></span>
<span id="cb47-74"><a href="#cb47-74"></a>    <span class="op">{</span> <span class="op">}</span></span>
<span id="cb47-75"><a href="#cb47-75"></a></span>
<span id="cb47-76"><a href="#cb47-76"></a>    <span class="kw">auto</span> context<span class="op">()</span> <span class="op">-&gt;</span> new_context<span class="op">&amp;</span> <span class="op">{</span></span>
<span id="cb47-77"><a href="#cb47-77"></a>        <span class="cf">return</span> erased_ctx;</span>
<span id="cb47-78"><a href="#cb47-78"></a>    <span class="op">}</span></span>
<span id="cb47-79"><a href="#cb47-79"></a></span>
<span id="cb47-80"><a href="#cb47-80"></a>    <span class="co">// in fmt, this iterator is buffered, so we need to flush it</span></span>
<span id="cb47-81"><a href="#cb47-81"></a>    <span class="dt">void</span> flush<span class="op">()</span> <span class="op">{</span></span>
<span id="cb47-82"><a href="#cb47-82"></a>        <span class="op">(</span><span class="dt">void</span><span class="op">)</span>buffer<span class="op">.</span>out<span class="op">()</span>;</span>
<span id="cb47-83"><a href="#cb47-83"></a>    <span class="op">}</span></span>
<span id="cb47-84"><a href="#cb47-84"></a><span class="op">}</span>;</span>
<span id="cb47-85"><a href="#cb47-85"></a></span>
<span id="cb47-86"><a href="#cb47-86"></a><span class="co">// In the &quot;happy&quot; case (i.e. we&#39;re just using fmt::print), we don&#39;t need to do</span></span>
<span id="cb47-87"><a href="#cb47-87"></a><span class="co">// any of this, the args are already the correct type so copying them is fine.</span></span>
<span id="cb47-88"><a href="#cb47-88"></a><span class="co">// All we need to do is create a new context</span></span>
<span id="cb47-89"><a href="#cb47-89"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> CharT, <span class="kw">typename</span> OutputIt<span class="op">&gt;</span></span>
<span id="cb47-90"><a href="#cb47-90"></a><span class="kw">struct</span> retargeted_format_context<span class="op">&lt;</span>basic_format_context<span class="op">&lt;</span>OutputIt, CharT<span class="op">&gt;</span>, OutputIt<span class="op">&gt;</span></span>
<span id="cb47-91"><a href="#cb47-91"></a><span class="op">{</span></span>
<span id="cb47-92"><a href="#cb47-92"></a>    basic_format_context<span class="op">&lt;</span>OutputIt, CharT<span class="op">&gt;</span> ctx;</span>
<span id="cb47-93"><a href="#cb47-93"></a></span>
<span id="cb47-94"><a href="#cb47-94"></a>    retargeted_format_context<span class="op">(</span>basic_format_context<span class="op">&lt;</span>OutputIt, CharT<span class="op">&gt;&amp;</span> ctx, OutputIt it<span class="op">)</span></span>
<span id="cb47-95"><a href="#cb47-95"></a>        <span class="op">:</span> ctx<span class="op">(</span>it, ctx<span class="op">.</span>args<span class="op">()</span>, ctx<span class="op">.</span>locale<span class="op">())</span></span>
<span id="cb47-96"><a href="#cb47-96"></a>    <span class="op">{</span> <span class="op">}</span></span>
<span id="cb47-97"><a href="#cb47-97"></a></span>
<span id="cb47-98"><a href="#cb47-98"></a>    <span class="kw">auto</span> context<span class="op">()</span> <span class="op">-&gt;</span> basic_format_context<span class="op">&lt;</span>OutputIt, CharT<span class="op">&gt;&amp;</span> <span class="op">{</span> <span class="cf">return</span> ctx; <span class="op">}</span></span>
<span id="cb47-99"><a href="#cb47-99"></a></span>
<span id="cb47-100"><a href="#cb47-100"></a>    <span class="dt">void</span> flush<span class="op">()</span> <span class="op">{</span> <span class="op">}</span></span>
<span id="cb47-101"><a href="#cb47-101"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>You can see this in the implementation I shared <span class="citation" data-cites="fmt-impl">[<a href="#ref-fmt-impl" role="doc-biblioref">fmt-impl</a>]</span>, on lines 65-140.</p>
<p>We don’t strictly need to provide <code class="sourceCode cpp">retargeted_format_context</code> just to format ranges (the implementation would do something like this internally). But if users want to be able to solve this problem (e.g. fill/pad/align for a user-defined type where all you have is <code class="sourceCode cpp">formatter<span class="op">&lt;</span>T<span class="op">&gt;</span></code> for unknown <code class="sourceCode cpp">T</code>) for any of their own types, they’ll need to do something like this as well, so this functionality should be provided to let them do that.</p>
<h3 data-number="3.4.2" id="manipulating-basic_format_parse_context-to-search-for-sentinels"><span class="header-section-number">3.4.2</span> Manipulating <code class="sourceCode cpp">basic_format_parse_context</code> to search for sentinels<a href="#manipulating-basic_format_parse_context-to-search-for-sentinels" class="self-link"></a></h3>
<p>Even though this paper is no longer proposing complex <code class="sourceCode cpp">pair</code> and <code class="sourceCode cpp">tuple</code> support, it’s still useful to discuss one of the examples that could have been supported:</p>
<blockquote>
<div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-1"></a>fmt<span class="op">::</span>format<span class="op">(</span><span class="st">&quot;{:|#x|*^10}&quot;</span>, std<span class="op">::</span>pair<span class="op">(</span><span class="dv">42</span>, <span class="st">&quot;hello&quot;</span><span class="bu">s</span><span class="op">))</span>;</span></code></pre></div>
</blockquote>
<p>In order for this to work, the <code class="sourceCode cpp">formatter<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> object needs to be passed a context that just contains the string <code class="sourceCode cpp"><span class="st">&quot;#x&quot;</span></code> and the <code class="sourceCode cpp">formatter<span class="op">&lt;</span>string<span class="op">&gt;</span></code> object needs to be passed a context that just contains the string <code class="sourceCode cpp"><span class="st">&quot;*^10&quot;</span></code> (or possibly <code class="sourceCode cpp"><span class="st">&quot;*^10}&quot;</span></code>). This is because <code class="sourceCode cpp">formatter<span class="op">&lt;</span>T<span class="op">&gt;::</span>parse</code> must consume the whole context. That’s the API.</p>
<p>But <code class="sourceCode cpp">basic_format_parse_context</code> does not provide a way for you to take a slice of it, and we can’t just construct a new object because of the dynamic argument counting support. Not just <em>any</em> context, but <em>specifically that one</em>.</p>
<p>Tim’s suggested design for how to even do specifiers for <code class="sourceCode cpp">pair</code> also came with a suggested implementation: use a <code class="sourceCode cpp">sentry</code>-like type that temporarily modifies the context and restores it later. The use of this type looks like this:</p>
<blockquote>
<div class="sourceCode" id="cb49"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb49-1"><a href="#cb49-1"></a><span class="kw">auto</span> <span class="kw">const</span> delim <span class="op">=</span> <span class="op">*</span>begin<span class="op">++</span>;</span>
<span id="cb49-2"><a href="#cb49-2"></a>ctx<span class="op">.</span>advance_to<span class="op">(</span>begin<span class="op">)</span>;</span>
<span id="cb49-3"><a href="#cb49-3"></a>tuple_for_each_index<span class="op">(</span>underlying, <span class="op">[&amp;](</span><span class="kw">auto</span> I, <span class="kw">auto</span><span class="op">&amp;</span> f<span class="op">){</span></span>
<span id="cb49-4"><a href="#cb49-4"></a>    <span class="kw">auto</span> next_delim <span class="op">=</span> std<span class="op">::</span>find<span class="op">(</span>ctx<span class="op">.</span>begin<span class="op">()</span>, end, delim<span class="op">)</span>;</span>
<span id="cb49-5"><a href="#cb49-5"></a>    <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>I <span class="op">+</span> <span class="dv">1</span> <span class="op">&lt;</span> <span class="kw">sizeof</span><span class="op">...(</span>Ts<span class="op">))</span> <span class="op">{</span></span>
<span id="cb49-6"><a href="#cb49-6"></a>        <span class="cf">if</span> <span class="op">(</span>next_delim <span class="op">==</span> end<span class="op">)</span> <span class="op">{</span></span>
<span id="cb49-7"><a href="#cb49-7"></a>            <span class="cf">throw</span> fmt<span class="op">::</span>format_error<span class="op">(</span><span class="st">&quot;ran out of specifiers&quot;</span><span class="op">)</span>;</span>
<span id="cb49-8"><a href="#cb49-8"></a>        <span class="op">}</span></span>
<span id="cb49-9"><a href="#cb49-9"></a>    <span class="op">}</span></span>
<span id="cb49-10"><a href="#cb49-10"></a></span>
<span id="cb49-11"><a href="#cb49-11"></a>    end_sentry _<span class="op">(</span>ctx, next_delim<span class="op">)</span>;</span>
<span id="cb49-12"><a href="#cb49-12"></a>    <span class="kw">auto</span> i <span class="op">=</span> f<span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb49-13"><a href="#cb49-13"></a>    <span class="cf">if</span> <span class="op">(</span>i <span class="op">!=</span> next_delim <span class="op">&amp;&amp;</span> <span class="op">*</span>i <span class="op">!=</span> <span class="ch">&#39;}&#39;</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb49-14"><a href="#cb49-14"></a>        <span class="cf">throw</span> fmt<span class="op">::</span>format_error<span class="op">(</span><span class="st">&quot;this is broken&quot;</span><span class="op">)</span>;</span>
<span id="cb49-15"><a href="#cb49-15"></a>    <span class="op">}</span></span>
<span id="cb49-16"><a href="#cb49-16"></a></span>
<span id="cb49-17"><a href="#cb49-17"></a>    <span class="cf">if</span> <span class="op">(</span>next_delim <span class="op">!=</span> end<span class="op">)</span> <span class="op">{</span></span>
<span id="cb49-18"><a href="#cb49-18"></a>        <span class="op">++</span>i;</span>
<span id="cb49-19"><a href="#cb49-19"></a>    <span class="op">}</span></span>
<span id="cb49-20"><a href="#cb49-20"></a>    ctx<span class="op">.</span>advance_to<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb49-21"><a href="#cb49-21"></a><span class="op">})</span>;</span></code></pre></div>
</blockquote>
<p>This ensures that each element of the <code class="sourceCode cpp">pair</code>/<code class="sourceCode cpp">tuple</code> only sees its part of the whole parse string, which is the only part that it knows what to do anything with.</p>
<p>Without something like this in the library, it’d be impossible to do this sort of complex specifier parsing. You could support ranges (there, we only have one underlying element, so it parses to the end), but not pair or tuple. We <em>could</em> say that since pair and tuple are library types, the library should just Make This Work, but there are surely other examples of wanting to do this sort of thing and it doesn’t feel right to not allow users to do it too.</p>
<p>As with <code class="sourceCode cpp">retargeted_format_context</code>, if we adopted the <code class="sourceCode cpp">pair</code>/<code class="sourceCode cpp">tuple</code> specifiers design, we wouldn’t have to expose something like this in the standard library. The implementation would need to do it internally and it could do whatever it needs to do to get it done. But it’s still useful functionality to be able to export to users. And especially if we’re not going to adopt arbitrary pair/tuple specifiers, I think it’s important to give users the tools to experiment with them.</p>
<p>This design space is, thankfully, slightly easier than the previous problem: this is basically what you have to do. Not much choice, I don’t think.</p>
<h3 data-number="3.4.3" id="parsing-of-alignment-padding-and-width"><span class="header-section-number">3.4.3</span> Parsing of alignment, padding, and width<a href="#parsing-of-alignment-padding-and-width" class="self-link"></a></h3>
<p>The first two issues in this section are serious implementation issues that require design changes to <code class="sourceCode cpp"><span class="op">&lt;</span>format<span class="op">&gt;</span></code>. This one doesn’t <em>require</em> changes, and this paper won’t propose changes, but it’s worth pointing out nevertheless. Alignment, padding, and width are the most common and fairly universal specifiers. But we don’t provide a public API to actually parse them.</p>
<p>When implementing this in <code class="sourceCode cpp">fmt</code>, I just took advantage of <code class="sourceCode cpp">fmt</code>’s implementation details to make this a lot easier for myself: a type (<code class="sourceCode cpp">dynamic_format_specs<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;</span></code>) that holds all the specifier results, a function that understands those to let you write a padded/aligned string (<code class="sourceCode cpp">write</code>), and several parsing functions that are well designed to do the right thing if you have a unique set of specifiers you wish to parse (the appropriately-named <code class="sourceCode cpp">parse_align</code> and <code class="sourceCode cpp">parse_width</code>).</p>
<p>These don’t have to be standardized, as nothing in these functions is something that a user couldn’t write on their own. And this paper is big enough already, so it, again, won’t propose anything in this space. But it’s worth considering for the future.</p>
<h2 data-number="3.5" id="how-to-support-those-views-which-are-not-const-iterable"><span class="header-section-number">3.5</span> How to support those views which are not <code class="sourceCode cpp"><span class="kw">const</span></code>-iterable?<a href="#how-to-support-those-views-which-are-not-const-iterable" class="self-link"></a></h2>
<p>In a previous revision of this paper, this was a real problem since at the time <code class="sourceCode cpp">std<span class="op">::</span>format</code> accepted its arguments by <code class="sourceCode cpp"><span class="kw">const</span> Args<span class="op">&amp;...</span></code></p>
<p>However, <span class="citation" data-cites="P2418R2">[<a href="#ref-P2418R2" role="doc-biblioref">P2418R2</a>]</span> was speedily adopted specifically to address this issue, and now <code class="sourceCode cpp">std<span class="op">::</span>format</code> accepts its arguments by <code class="sourceCode cpp">Args<span class="op">&amp;&amp;...</span></code> This allows those views which are not <code class="sourceCode cpp"><span class="kw">const</span></code>-iterable to be mutably passed into <code class="sourceCode cpp">format<span class="op">()</span></code> and <code class="sourceCode cpp">print<span class="op">()</span></code> and then mutably into its formatter. To support both <code class="sourceCode cpp"><span class="kw">const</span></code> and non-<code class="sourceCode cpp"><span class="kw">const</span></code> formatting of ranges without too much boilerplate, we can do it this way:</p>
<blockquote>
<div class="sourceCode" id="cb50"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb50-1"><a href="#cb50-1"></a><span class="kw">template</span> <span class="op">&lt;</span>formattable V<span class="op">&gt;</span></span>
<span id="cb50-2"><a href="#cb50-2"></a><span class="kw">struct</span> range_formatter <span class="op">{</span></span>
<span id="cb50-3"><a href="#cb50-3"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> ParseContext<span class="op">&gt;</span></span>
<span id="cb50-4"><a href="#cb50-4"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> parse<span class="op">(</span>ParseContext<span class="op">&amp;)</span>;</span>
<span id="cb50-5"><a href="#cb50-5"></a></span>
<span id="cb50-6"><a href="#cb50-6"></a>    <span class="kw">template</span> <span class="op">&lt;</span>range R, <span class="kw">typename</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb50-7"><a href="#cb50-7"></a>        <span class="kw">requires</span> same_as<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span>, V<span class="op">&gt;</span></span>
<span id="cb50-8"><a href="#cb50-8"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> format<span class="op">(</span>R<span class="op">&amp;&amp;</span>, FormatContext<span class="op">&amp;)</span>;</span>
<span id="cb50-9"><a href="#cb50-9"></a><span class="op">}</span>;</span>
<span id="cb50-10"><a href="#cb50-10"></a></span>
<span id="cb50-11"><a href="#cb50-11"></a><span class="kw">template</span> <span class="op">&lt;</span>range R<span class="op">&gt;</span> <span class="kw">requires</span> formattable<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></span>
<span id="cb50-12"><a href="#cb50-12"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">:</span> range_formatter<span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></span>
<span id="cb50-13"><a href="#cb50-13"></a><span class="op">{</span> <span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p><code class="sourceCode cpp">range_formatter</code> allows reducing unnecessary template instantiations. Any range of <code class="sourceCode cpp"><span class="dt">int</span></code> is going to <code class="sourceCode cpp">parse</code> its specifiers the same way, there’s no need to re-instantiate that code n times. Such a type will also help users to write their own formatters, since they can have a member <code class="sourceCode cpp">range_formatter<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> to handle any range of <code class="sourceCode cpp"><span class="dt">int</span></code> (or <code class="sourceCode cpp"><span class="dt">int</span><span class="op">&amp;</span></code> or <code class="sourceCode cpp"><span class="dt">int</span> <span class="kw">const</span><span class="op">&amp;</span></code>) rather than having to have a specific <code class="sourceCode cpp">formatter<span class="op">&lt;</span>my_special_range<span class="op">&gt;</span></code>.</p>
<h2 data-number="3.6" id="what-additional-functionality"><span class="header-section-number">3.6</span> What additional functionality?<a href="#what-additional-functionality" class="self-link"></a></h2>
<p>There’s three layers of potential functionality:</p>
<ol type="1">
<li><p>Top-level printing of ranges: this is <code class="sourceCode cpp">fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}&quot;</span>, r<span class="op">)</span></code>;</p></li>
<li><p>A format-joiner which allows providing a a custom delimiter: this is provided in <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> under the spelling <code class="sourceCode cpp">fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{:02x}&quot;</span>, fmt<span class="op">::</span>join<span class="op">(</span>r, <span class="st">&quot;:&quot;</span><span class="op">))</span></code>. Previous revisions of the paper sought to simply standardize this under the name <code class="sourceCode cpp">std<span class="op">::</span>format_join</code>, but this paper has since evolved to both allow custom specifier directly to format <code class="sourceCode cpp">r</code> as well as now providing the ability to directly provide the delimiter. A <code class="sourceCode cpp">fmt<span class="op">::</span>join</code>-like facility is thus not necessary and not proposed.</p></li>
<li><p>A more involved version of a format-joiner which takes a delimiter and a callback that gets invoked on each element. fmt does not provide such a mechanism, though the Rust itertools library does:</p></li>
</ol>
<blockquote>
<div class="sourceCode" id="cb7"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">let</span> matrix <span class="op">=</span> [[<span class="dv">1</span><span class="op">.,</span> <span class="dv">2</span><span class="op">.,</span> <span class="dv">3</span><span class="op">.</span>]<span class="op">,</span></span>
<span id="cb7-2"><a href="#cb7-2"></a>              [<span class="dv">4</span><span class="op">.,</span> <span class="dv">5</span><span class="op">.,</span> <span class="dv">6</span><span class="op">.</span>]]<span class="op">;</span></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="kw">let</span> matrix_formatter <span class="op">=</span> matrix<span class="op">.</span>iter()<span class="op">.</span>format_with(<span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">,</span> <span class="op">|</span>row<span class="op">,</span> f<span class="op">|</span> <span class="op">{</span></span>
<span id="cb7-4"><a href="#cb7-4"></a>                                f(<span class="op">&amp;</span>row<span class="op">.</span>iter()<span class="op">.</span>format_with(<span class="st">&quot;, &quot;</span><span class="op">,</span> <span class="op">|</span>elt<span class="op">,</span> g<span class="op">|</span> g(<span class="op">&amp;</span>elt)))</span>
<span id="cb7-5"><a href="#cb7-5"></a>                              <span class="op">}</span>)<span class="op">;</span></span>
<span id="cb7-6"><a href="#cb7-6"></a><span class="pp">assert_eq!</span>(<span class="pp">format!</span>(<span class="st">&quot;{}&quot;</span><span class="op">,</span> matrix_formatter)<span class="op">,</span></span>
<span id="cb7-7"><a href="#cb7-7"></a>           <span class="st">&quot;1, 2, 3</span><span class="sc">\n</span><span class="st">4, 5, 6&quot;</span>)<span class="op">;</span></span></code></pre></div>
</blockquote>
<p>Even this example is also already solvable with the facilities suggested in this revision, as <code class="sourceCode cpp">format<span class="op">(</span><span class="st">&quot;{:ed[</span><span class="sc">\n</span><span class="st">]:e}&quot;</span>, matrix<span class="op">)</span></code> (or the <code class="sourceCode cpp"><span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span></code> delimiter can be provided dynamically). The one piece of flexibility <em>not</em> provided in this revision is, in the case of formatting a range of ranges, there is currently no ability to provide a custom bracket to the inner range. You either get the default <code class="sourceCode cpp"><span class="op">[]</span></code>s or you can get nothing, but you have no way of providing, say… <code class="sourceCode cpp"><span class="op">()</span></code>s or <code class="sourceCode cpp"><span class="op">&lt;&gt;</span></code> or <code class="sourceCode cpp">⦕⦖</code>s or whatever. This would have to be provided by either the user writing a custom formatter for their custom type, or a future extension of this paper which explores how to do custom brackets.</p>
<p>But given the wealth of functionality that is available, that’s pretty great.</p>
<h3 data-number="3.6.1" id="fmtjoin"><span class="header-section-number">3.6.1</span> <code class="sourceCode cpp">fmt<span class="op">::</span>join</code><a href="#fmtjoin" class="self-link"></a></h3>
<p>If we were not going to support <a href="#dynamic-delimiter-for-ranges">dynamic</a> and <a href="#static-delimiter-for-ranges">static</a> delimiters for ranges, then we need some other mechanism to provide a custom delimiter. That mechanism exists in <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> already under the name <code class="sourceCode cpp">fmt<span class="op">::</span>join</code>.</p>
<p>It works like this:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Format String</strong>
</div></th>
<th><div style="text-align:center">
<strong>Contents</strong>
</div></th>
<th><div style="text-align:center">
<strong>Formatted Output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">fmt<span class="op">::</span>join<span class="op">(</span>std<span class="op">::</span>vector<span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>, <span class="st">&quot;, &quot;</span><span class="op">)</span></code></td>
<td><code class="x">1, 2, 3</code></td>
</tr>
<tr class="even">
<td><code class="x">[{}]</code></td>
<td><code class="sourceCode cpp">fmt<span class="op">::</span>join<span class="op">(</span>std<span class="op">::</span>vector<span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>, <span class="st">&quot;, &quot;</span><span class="op">)</span></code></td>
<td><code class="x">[1, 2, 3]</code></td>
</tr>
<tr class="odd">
<td><code class="x">[{}]</code></td>
<td><code class="sourceCode cpp">fmt<span class="op">::</span>join<span class="op">(</span>std<span class="op">::</span>vector<span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>, <span class="st">&quot;--&quot;</span><span class="op">)</span></code></td>
<td><code class="x">[1--2--3]</code></td>
</tr>
<tr class="even">
<td><code class="x">[{}]</code></td>
<td><code class="sourceCode cpp">fmt<span class="op">::</span>join<span class="op">(</span>std<span class="op">::</span>vector<span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>, <span class="st">&quot;--&quot;</span><span class="bu">s</span><span class="op">)</span></code></td>
<td><code class="x">[1--2--3]</code></td>
</tr>
<tr class="odd">
<td><code class="x">{:x}</code></td>
<td><code class="sourceCode cpp">fmt<span class="op">::</span>join<span class="op">(</span>std<span class="op">::</span>vector<span class="op">{</span><span class="dv">10</span>, <span class="dv">20</span>, <span class="dv">30</span><span class="op">}</span>, <span class="st">&quot;:&quot;</span><span class="op">)</span></code></td>
<td><code class="x">a:14:1e</code></td>
</tr>
<tr class="even">
<td><code class="x">{:#04X}</code></td>
<td><code class="sourceCode cpp">fmt<span class="op">::</span>join<span class="op">(</span>std<span class="op">::</span>vector<span class="op">{</span><span class="dv">10</span>, <span class="dv">20</span>, <span class="dv">30</span><span class="op">}</span>, <span class="st">&quot;:&quot;</span><span class="op">)</span></code></td>
<td><code class="x">0X0A:0X14:0X1E</code></td>
</tr>
<tr class="odd">
<td><code class="x">{}</code></td>
<td><code class="sourceCode cpp">fmt<span class="op">::</span>join<span class="op">(</span>std<span class="op">::</span>vector<span class="op">{</span><span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span>, <span class="st">&quot;world&quot;</span><span class="bu">s</span><span class="op">}</span>, <span class="st">&quot;, &quot;</span><span class="op">)</span></code></td>
<td><code class="x">h    llo, world</code></td>
</tr>
<tr class="even">
<td><code class="x">{:?}</code></td>
<td><code class="sourceCode cpp">fmt<span class="op">::</span>join<span class="op">(</span>std<span class="op">::</span>vector<span class="op">{</span><span class="st">&quot;h</span><span class="sc">\t</span><span class="st">llo&quot;</span><span class="bu">s</span>, <span class="st">&quot;world&quot;</span><span class="bu">s</span><span class="op">}</span>, <span class="st">&quot;, &quot;</span><span class="op">)</span></code></td>
<td><code class="x">&quot;h\tllo&quot;, &quot;world&quot;</code></td>
</tr>
</tbody>
</table>
<p><code class="sourceCode cpp">std<span class="op">::</span>format_join</code> (since we already have a <code class="sourceCode cpp">std<span class="op">::</span>views<span class="op">::</span>join</code> and none of the formatting is in a <code class="sourceCode cpp">fmt</code> namespace) will accept a <code class="sourceCode cpp">viewable_range</code> of <code class="sourceCode cpp">formattable</code> (based on the range’s <code class="sourceCode cpp">reference</code> type) and a delimiter which is convertible to <code class="sourceCode cpp"><span class="op">(</span>w<span class="op">)</span>string_view</code>, and produce an <code class="sourceCode cpp">std<span class="op">::</span><em>format-join-view</em></code> object. That object will take as a specifier whatever the underlying type accepts, and use that result to format each element, using the provided delimiter. Unlike the default ranges formatter, strings and chars are not printed escaped/quoted: users need to provide <code class="sourceCode cpp"><span class="op">?</span></code> for that functionality.</p>
<p>Note that <code class="sourceCode cpp">std<span class="op">::</span>format_join</code> does not (and cannot) support pad/align/width. But some people might prefer reading <code class="sourceCode cpp">join<span class="op">(</span>r, <span class="st">&quot;-&quot;</span><span class="op">)</span></code> in code over something like <code class="sourceCode cpp">d<span class="op">{}</span></code> with a <code class="sourceCode cpp"><span class="st">&quot;-&quot;</span></code> somewhere or <code class="sourceCode cpp">d<span class="op">[-]</span></code>. For those people, it is pretty straightforward to implement <code class="sourceCode cpp">fmt<span class="op">::</span>join</code>, and that implementation is provided here (even though the paper is not proposing that we standardize this facility, because I’ve become convinced at this point that it is strictly worse than the static/dynamic delimiter approach that is proposed in this facility).</p>
<blockquote>
<div class="sourceCode" id="cb51"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb51-1"><a href="#cb51-1"></a><span class="kw">template</span> <span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>input_range V<span class="op">&gt;</span></span>
<span id="cb51-2"><a href="#cb51-2"></a>    <span class="kw">requires</span> std<span class="op">::</span>ranges<span class="op">::</span>view<span class="op">&lt;</span>V<span class="op">&gt;</span></span>
<span id="cb51-3"><a href="#cb51-3"></a>          <span class="op">&amp;&amp;</span> formattable<span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>range_reference_t<span class="op">&lt;</span>V<span class="op">&gt;&gt;</span></span>
<span id="cb51-4"><a href="#cb51-4"></a><span class="kw">struct</span> format_join_view <span class="op">{</span></span>
<span id="cb51-5"><a href="#cb51-5"></a>    V v;</span>
<span id="cb51-6"><a href="#cb51-6"></a>    fmt<span class="op">::</span>string_view delim;</span>
<span id="cb51-7"><a href="#cb51-7"></a><span class="op">}</span>;</span>
<span id="cb51-8"><a href="#cb51-8"></a></span>
<span id="cb51-9"><a href="#cb51-9"></a><span class="kw">template</span> <span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>input_range V<span class="op">&gt;</span></span>
<span id="cb51-10"><a href="#cb51-10"></a><span class="kw">struct</span> fmt<span class="op">::</span>formatter<span class="op">&lt;</span>format_join_view<span class="op">&lt;</span>V<span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb51-11"><a href="#cb51-11"></a>    fmt<span class="op">::</span>formatter<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>range_reference_t<span class="op">&lt;</span>V<span class="op">&gt;&gt;&gt;</span> underlying;</span>
<span id="cb51-12"><a href="#cb51-12"></a></span>
<span id="cb51-13"><a href="#cb51-13"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> ParseContext<span class="op">&gt;</span></span>
<span id="cb51-14"><a href="#cb51-14"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> parse<span class="op">(</span>ParseContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb51-15"><a href="#cb51-15"></a>        <span class="cf">return</span> underlying<span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb51-16"><a href="#cb51-16"></a>    <span class="op">}</span></span>
<span id="cb51-17"><a href="#cb51-17"></a></span>
<span id="cb51-18"><a href="#cb51-18"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R, <span class="kw">typename</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb51-19"><a href="#cb51-19"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> format<span class="op">(</span>R<span class="op">&amp;&amp;</span> r, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb51-20"><a href="#cb51-20"></a>        <span class="kw">auto</span> it <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>r<span class="op">.</span>v<span class="op">)</span>;</span>
<span id="cb51-21"><a href="#cb51-21"></a>        <span class="kw">auto</span> out <span class="op">=</span> ctx<span class="op">.</span>out<span class="op">()</span>;</span>
<span id="cb51-22"><a href="#cb51-22"></a>        <span class="cf">if</span> <span class="op">(</span>it <span class="op">!=</span> std<span class="op">::</span>ranges<span class="op">::</span>end<span class="op">(</span>r<span class="op">.</span>v<span class="op">))</span> <span class="op">{</span></span>
<span id="cb51-23"><a href="#cb51-23"></a>            out <span class="op">=</span> underlying<span class="op">.</span>format<span class="op">(*</span>it, ctx<span class="op">)</span>;</span>
<span id="cb51-24"><a href="#cb51-24"></a>            <span class="cf">for</span> <span class="op">(++</span>it; it <span class="op">!=</span> std<span class="op">::</span>ranges<span class="op">::</span>end<span class="op">(</span>r<span class="op">.</span>v<span class="op">)</span>; <span class="op">++</span>it<span class="op">)</span> <span class="op">{</span></span>
<span id="cb51-25"><a href="#cb51-25"></a>                ctx<span class="op">.</span>advance_to<span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>copy<span class="op">(</span>r<span class="op">.</span>delim, out<span class="op">).</span>out<span class="op">)</span>;</span>
<span id="cb51-26"><a href="#cb51-26"></a>                out <span class="op">=</span> underlying<span class="op">.</span>format<span class="op">(*</span>it, ctx<span class="op">)</span>;</span>
<span id="cb51-27"><a href="#cb51-27"></a>            <span class="op">}</span></span>
<span id="cb51-28"><a href="#cb51-28"></a>        <span class="op">}</span></span>
<span id="cb51-29"><a href="#cb51-29"></a>        <span class="cf">return</span> out;</span>
<span id="cb51-30"><a href="#cb51-30"></a>    <span class="op">}</span></span>
<span id="cb51-31"><a href="#cb51-31"></a><span class="op">}</span>;</span>
<span id="cb51-32"><a href="#cb51-32"></a></span>
<span id="cb51-33"><a href="#cb51-33"></a><span class="kw">template</span> <span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>viewable_range R<span class="op">&gt;</span></span>
<span id="cb51-34"><a href="#cb51-34"></a>    <span class="kw">requires</span> formattable<span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></span>
<span id="cb51-35"><a href="#cb51-35"></a><span class="kw">auto</span> format_join<span class="op">(</span>R<span class="op">&amp;&amp;</span> r, fmt<span class="op">::</span>string_view delim<span class="op">)</span> <span class="op">{</span></span>
<span id="cb51-36"><a href="#cb51-36"></a>    <span class="cf">return</span> format_join_view<span class="op">{</span>std<span class="op">::</span>views<span class="op">::</span>all<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>R<span class="op">&gt;(</span>r<span class="op">))</span>, delim<span class="op">}</span>;</span>
<span id="cb51-37"><a href="#cb51-37"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<h2 data-number="3.7" id="format-or-stdcout"><span class="header-section-number">3.7</span> <code class="sourceCode cpp">format</code> or <code class="sourceCode cpp">std<span class="op">::</span>cout</code>?<a href="#format-or-stdcout" class="self-link"></a></h2>
<p>Just <code class="sourceCode cpp">format</code> is sufficient.</p>
<h2 data-number="3.8" id="what-about-vectorbool"><span class="header-section-number">3.8</span> What about <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span></code>?<a href="#what-about-vectorbool" class="self-link"></a></h2>
<p>Nobody expected this section.</p>
<p>The <code class="sourceCode cpp">value_type</code> of this range is <code class="sourceCode cpp"><span class="dt">bool</span></code>, which is formattable. But the <code class="sourceCode cpp">reference</code> type of this range is <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code>, which is not. In order to make the whole type formattable, we can either make <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code> formattable (and thus, in general, a range is formattable if its <code class="sourceCode cpp">reference</code> types is formattable) or allow formatting to fall back to constructing a <code class="sourceCode cpp">value_type</code> for each <code class="sourceCode cpp">reference</code> (and thus, in general, a range is formattable if either its <code class="sourceCode cpp">reference</code> type or its <code class="sourceCode cpp">value_type</code> is formattable).</p>
<p>For most ranges, the <code class="sourceCode cpp">value_type</code> is <code class="sourceCode cpp">remove_cvref_t<span class="op">&lt;</span>reference<span class="op">&gt;</span></code>, so there’s no distinction here between the two options. And even for <code class="sourceCode cpp">zip</code> <span class="citation" data-cites="P2321R2">[<a href="#ref-P2321R2" role="doc-biblioref">P2321R2</a>]</span>, there’s still not much distinction since it just wraps this question in tuple since again for most ranges the types will be something like <code class="sourceCode cpp">tuple<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code> vs <code class="sourceCode cpp">tuple<span class="op">&lt;</span>T<span class="op">&amp;</span>, U <span class="kw">const</span><span class="op">&amp;&gt;</span></code>, so again there isn’t much distinction.</p>
<p><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span></code> is one of the very few ranges in which the two types are truly quite different. So it doesn’t offer much in the way of a good example here, since <code class="sourceCode cpp"><span class="dt">bool</span></code> is cheaply constructible from <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code>. Though it’s also very cheap to provide a formatter specialization for <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code>.</p>
<p>Rather than having the library provide a default fallback that lifts all the <code class="sourceCode cpp">reference</code> types to <code class="sourceCode cpp">value_type</code>s, which may be arbitrarily expensive for unknown ranges, this paper proposes a format specialization for <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code>. This type is actually defined as <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span>, Alloc<span class="op">&gt;::</span>reference</code>, so the wording for this aspect will be a little awkward (we’ll need to provide a type trait <code class="sourceCode cpp"><em>is-vector-bool-reference</em><span class="op">&lt;</span>R<span class="op">&gt;</span></code>, etc., but this is a problem for the wording and the implementation to deal with).</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="proposal"><span class="header-section-number">4</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>The standard library will provide the following utilities:</p>
<ul>
<li>A <code class="sourceCode cpp">formattable</code> concept.</li>
<li>A <code class="sourceCode cpp">range_formatter<span class="op">&lt;</span>V<span class="op">&gt;</span></code> that uses a <code class="sourceCode cpp">formatter<span class="op">&lt;</span>V<span class="op">&gt;</span></code> to <code class="sourceCode cpp">parse</code> and <code class="sourceCode cpp">format</code> a range whose <code class="sourceCode cpp">reference</code> is similar to <code class="sourceCode cpp">V</code>. This can accept a specifier on the range (align/pad/width as well as string/map/debug/empty/static delimiter/dynamic delimiter) and on the underlying element (which will be applied to every element in the range).</li>
<li>A <code class="sourceCode cpp">tuple_formatter<span class="op">&lt;</span>tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;</span></code> that uses a <code class="sourceCode cpp">formatter<span class="op">&lt;</span>T<span class="op">&gt;</span></code> for each <code class="sourceCode cpp">T</code> in <code class="sourceCode cpp">Ts<span class="op">...</span></code> to <code class="sourceCode cpp">parse</code> and <code class="sourceCode cpp">format</code> either a <code class="sourceCode cpp">pair</code>, <code class="sourceCode cpp">tuple</code>, or <code class="sourceCode cpp">array</code> with appropriate elements. This can accept a specifier on the tuple-like (align/pad/width as well as map/static delimiter/dynamic delimiter), but will not accept any specifier the underlying elements.</li>
<li>A <code class="sourceCode cpp">retargeted_format_context</code> facility that allows the user to construct a new <code class="sourceCode cpp"><span class="op">(</span>w<span class="op">)</span>format_context</code> with a custom output iterator.</li>
<li>An <code class="sourceCode cpp">end_sentry</code> facility that allows the user to manipulate the parse context’s range, for generic parsing purposes (so that users can, if they want, write their own arbitrarily-complex pair/tuple formatting).</li>
</ul>
<p>The standard library should add specializations of <code class="sourceCode cpp">formatter</code> for:</p>
<ul>
<li>any type <code class="sourceCode cpp">R</code> that is a <code class="sourceCode cpp">range</code> whose <code class="sourceCode cpp">reference</code> is <code class="sourceCode cpp">formattable</code>, which inherits from <code class="sourceCode cpp">range_formatter<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>ranges<span class="op">::</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;&gt;</span></code></li>
<li><code class="sourceCode cpp">pair<span class="op">&lt;</span>T, U<span class="op">&gt;</span></code> if <code class="sourceCode cpp">T</code> and <code class="sourceCode cpp">U</code> are <code class="sourceCode cpp">formattable</code>, which inherits from <code class="sourceCode cpp">tuple_formatter<span class="op">&lt;</span>tuple<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>T<span class="op">&gt;</span>, remove_cvref_t<span class="op">&lt;</span>U<span class="op">&gt;&gt;&gt;</span></code></li>
<li><code class="sourceCode cpp">tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;</span></code> if all of <code class="sourceCode cpp">Ts<span class="op">...</span></code> are <code class="sourceCode cpp">formattable</code>, which inherits from <code class="sourceCode cpp">tuple_formatter<span class="op">&lt;</span>tuple<span class="op">&lt;</span>remove_cvref_t<span class="op">&lt;</span>Ts<span class="op">&gt;...&gt;&gt;</span></code></li>
</ul>
<p>Note that the <code class="sourceCode cpp">pair</code> and <code class="sourceCode cpp">tuple</code> formatters both inherit from <code class="sourceCode cpp">tuple_formatter<span class="op">&lt;</span>tuple<span class="op">&lt;</span>Ts<span class="op">...&gt;&gt;</span></code>. This is to keep the pattern of defaulting the <code class="sourceCode cpp">charT</code> parameter as the second parameter, which otherwise would have to be flipped and look exceedingly awkward.</p>
<p>Additionally, the standard library should provide the following more specific specializations of <code class="sourceCode cpp">formatter</code>:</p>
<ul>
<li><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span>, Alloc<span class="op">&gt;::</span>reference</code> (which formats as a <code class="sourceCode cpp"><span class="dt">bool</span></code>)</li>
<li>all the associative maps (<code class="sourceCode cpp">map</code>, <code class="sourceCode cpp">multimap</code>, <code class="sourceCode cpp">unordered_map</code>, <code class="sourceCode cpp">unordered_multimap</code>) if their respective key/value types are <code class="sourceCode cpp">formattable</code>. This accepts the same set of specifiers as any other range, except by <em>default</em> it will format as <code class="sourceCode cpp"><span class="op">{</span>k<span class="op">:</span> v, k<span class="op">:</span> v<span class="op">}</span></code> instead of <code class="sourceCode cpp"><span class="op">[(</span>k, v<span class="op">)</span>, <span class="op">(</span>k, v<span class="op">)]</span></code></li>
<li>all the associative sets (<code class="sourceCode cpp">sets</code>, <code class="sourceCode cpp">multiset</code>, <code class="sourceCode cpp">unordered_set</code>, <code class="sourceCode cpp">unordered_multiset</code>) if their respective key/value types are <code class="sourceCode cpp">formattable</code>. This accepts the same set of specifiers as any other range, except by <em>default</em> it will format as <code class="sourceCode cpp"><span class="op">{</span>v1, v2<span class="op">}</span></code> instead of <code class="sourceCode cpp"><span class="op">[</span>v1, v2<span class="op">]</span></code></li>
</ul>
<p>Formatting for <code class="sourceCode cpp">string</code>, <code class="sourceCode cpp">string_view</code>, and <code class="sourceCode cpp"><span class="dt">char</span></code>/<code class="sourceCode cpp"><span class="dt">wchar_t</span></code> will gain a <code class="sourceCode cpp"><span class="op">?</span></code> specifier, which causes these types to be printed as escaped and quoted if provided. Ranges and tuples will, by default, print their elements as escaped and quoted, unless the user provides a specifier for the element.</p>
<h2 data-number="4.1" id="wording"><span class="header-section-number">4.1</span> Wording<a href="#wording" class="self-link"></a></h2>
<p>This wording is very much incomplete, in the interests of time to try to get this paper in C++23.</p>
<p>The wording here is grouped by functionality added rather than linearly going through the standard text.</p>
<h3 data-number="4.1.1" id="concept-formattable"><span class="header-section-number">4.1.1</span> Concept <code class="sourceCode cpp">formattable</code><a href="#concept-formattable" class="self-link"></a></h3>
<p>First, we need to define a user-facing concept. We need this because we need to constrain <code class="sourceCode cpp">formatter</code> specializations on whether the underlying elements of the <code class="sourceCode cpp">pair</code>/<code class="sourceCode cpp">tuple</code>/range are formattable, and users would need to do the same kind of thing for their types. This is tricky since formatting involves so many different types, so this concept will never be perfect, so instead we’re trying to be good enough.</p>
<p>Change <span>20.20.1 <a href="https://wg21.link/format.syn">[format.syn]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb52"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb52-1"><a href="#cb52-1"></a>namespace std {</span>
<span id="cb52-2"><a href="#cb52-2"></a>  // ...</span>
<span id="cb52-3"><a href="#cb52-3"></a>  // [format.formatter], formatter</span>
<span id="cb52-4"><a href="#cb52-4"></a>  template&lt;class T, class charT = char&gt; struct formatter;</span>
<span id="cb52-5"><a href="#cb52-5"></a></span>
<span id="cb52-6"><a href="#cb52-6"></a>  // [format.parse.ctx], class template basic_format_parse_context</span>
<span id="cb52-7"><a href="#cb52-7"></a>  template&lt;class charT&gt; class basic_format_parse_context;</span>
<span id="cb52-8"><a href="#cb52-8"></a>  using format_parse_context = basic_format_parse_context&lt;char&gt;;</span>
<span id="cb52-9"><a href="#cb52-9"></a>  using wformat_parse_context = basic_format_parse_context&lt;wchar_t&gt;;</span>
<span id="cb52-10"><a href="#cb52-10"></a><span class="va">+ // [format.formattable], formattable</span></span>
<span id="cb52-11"><a href="#cb52-11"></a><span class="va">+ template&lt;class T, class charT&gt;</span></span>
<span id="cb52-12"><a href="#cb52-12"></a><span class="va">+   concept formattable = <em>see below</em>;</span></span>
<span id="cb52-13"><a href="#cb52-13"></a>  // ...</span>
<span id="cb52-14"><a href="#cb52-14"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Add a clause [format.formattable] under <span>20.20.6 <a href="https://wg21.link/format.formatter">[format.formatter]</a></span> and likely after <span>20.20.6.1 <a href="https://wg21.link/formatter.requirements">[formatter.requirements]</a></span>:</p>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">1</a></span> Let <code class="sourceCode cpp"><em>fmt-iter-for</em><span class="op">&lt;</span>charT<span class="op">&gt;</span></code> be an implementation-defined type that models <code class="sourceCode cpp">output_iterator<span class="op">&lt;</span><span class="kw">const</span> charT<span class="op">&amp;&gt;</span></code> ([iterator.concept.output]).</p>
<div class="sourceCode" id="cb53"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb53-1"><a href="#cb53-1"></a>template&lt;class T, class charT&gt;</span>
<span id="cb53-2"><a href="#cb53-2"></a>concept <em>formattable-impl</em> =</span>
<span id="cb53-3"><a href="#cb53-3"></a>    semiregular&lt;formatter&lt;T, charT&gt;&gt; &amp;&amp;</span>
<span id="cb53-4"><a href="#cb53-4"></a>    requires (formatter&lt;T, charT&gt; f,</span>
<span id="cb53-5"><a href="#cb53-5"></a>              const formatter&lt;T, charT&gt; cf,</span>
<span id="cb53-6"><a href="#cb53-6"></a>              T t,</span>
<span id="cb53-7"><a href="#cb53-7"></a>              basic_format_context&lt;<em>fmt-iter-for</em>&lt;charT&gt;, charT&gt; fc,</span>
<span id="cb53-8"><a href="#cb53-8"></a>              basic_format_parse_context&lt;charT&gt; pc) {</span>
<span id="cb53-9"><a href="#cb53-9"></a>        { f.parse(pc) } -&gt; same_as&lt;basic_format_parse_context&lt;charT&gt;::iterator&gt;;</span>
<span id="cb53-10"><a href="#cb53-10"></a>        { cf.format(t, fc) } -&gt; same_as&lt;<em>fmt-iter-for</em>&lt;charT&gt;&gt;;</span>
<span id="cb53-11"><a href="#cb53-11"></a>    };</span>
<span id="cb53-12"><a href="#cb53-12"></a></span>
<span id="cb53-13"><a href="#cb53-13"></a>template&lt;class T, class charT&gt;</span>
<span id="cb53-14"><a href="#cb53-14"></a>concept formattable = <em>formattable-impl</em>&lt;remove_cvref_t&lt;T&gt;, charT&gt;;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">2</a></span> A type <code class="sourceCode cpp">T</code> and a character type <code class="sourceCode cpp">charT</code> model <code class="sourceCode cpp">formattable</code> if <code class="sourceCode cpp">formatter<span class="op">&lt;</span>T, charT<span class="op">&gt;</span></code> meets the <em>Formatter</em> requirements ([formatter.requirements]).</p>
</div>
</blockquote>
<h3 data-number="4.1.2" id="retargeting-format_context"><span class="header-section-number">4.1.2</span> Retargeting <code class="sourceCode cpp">format_context</code><a href="#retargeting-format_context" class="self-link"></a></h3>
<p>Add to… somewhere:</p>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb54"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb54-1"><a href="#cb54-1"></a>// [format.retargeted.context]</span>
<span id="cb54-2"><a href="#cb54-2"></a>template&lt;class Context, class OutputIt&gt;</span>
<span id="cb54-3"><a href="#cb54-3"></a> struct retargeted_format_context;</span></code></pre></div>
</div>
</blockquote>
<p>And:</p>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">1</a></span> <code class="sourceCode cpp">retargeted_format_context</code> creates a new <code class="sourceCode cpp">basic_format_context</code> to allow for formatting into a custom buffer. [<em>Note</em>: This allows a <code class="sourceCode cpp">formatter</code> to change the output that a different <code class="sourceCode cpp">formatter</code> produces, for instance to add alignment or padding. <em>-end note</em>]</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">2</a></span> [<em>Example</em>:</p>
<div class="sourceCode" id="cb55"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb55-1"><a href="#cb55-1"></a><span class="kw">struct</span> NoCapes <span class="op">{</span></span>
<span id="cb55-2"><a href="#cb55-2"></a>    string_view value;</span>
<span id="cb55-3"><a href="#cb55-3"></a><span class="op">}</span>;</span>
<span id="cb55-4"><a href="#cb55-4"></a></span>
<span id="cb55-5"><a href="#cb55-5"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span></span>
<span id="cb55-6"><a href="#cb55-6"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>NoCapes<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb55-7"><a href="#cb55-7"></a>    formatter<span class="op">&lt;</span>string_view<span class="op">&gt;</span> fmt;</span>
<span id="cb55-8"><a href="#cb55-8"></a></span>
<span id="cb55-9"><a href="#cb55-9"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> ParseContext<span class="op">&gt;</span></span>
<span id="cb55-10"><a href="#cb55-10"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> parse<span class="op">(</span>ParseContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb55-11"><a href="#cb55-11"></a>        <span class="cf">return</span> fmt<span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb55-12"><a href="#cb55-12"></a>    <span class="op">}</span></span>
<span id="cb55-13"><a href="#cb55-13"></a></span>
<span id="cb55-14"><a href="#cb55-14"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb55-15"><a href="#cb55-15"></a>    <span class="kw">auto</span> format<span class="op">(</span>NoCapes nc, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb55-16"><a href="#cb55-16"></a>        vector<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;</span> edna;</span>
<span id="cb55-17"><a href="#cb55-17"></a>        retargeted_format_context new_ctx<span class="op">(</span>ctx, back_inserter<span class="op">(</span>edna<span class="op">))</span>;</span>
<span id="cb55-18"><a href="#cb55-18"></a>        fmt<span class="op">.</span>format<span class="op">(</span>nc<span class="op">.</span>value, new_ctx<span class="op">.</span>context<span class="op">())</span>;</span>
<span id="cb55-19"><a href="#cb55-19"></a>        new_ctx<span class="op">.</span>flush<span class="op">()</span>;</span>
<span id="cb55-20"><a href="#cb55-20"></a></span>
<span id="cb55-21"><a href="#cb55-21"></a>        erase_if<span class="op">(</span>edna, <span class="op">[](</span><span class="dt">char</span> c<span class="op">){</span></span>
<span id="cb55-22"><a href="#cb55-22"></a>            <span class="kw">constexpr</span> string_view capes <span class="op">=</span> <span class="st">&quot;capes&quot;</span>;</span>
<span id="cb55-23"><a href="#cb55-23"></a>            <span class="cf">return</span> capes<span class="op">.</span>contains<span class="op">(</span>c<span class="op">)</span>;</span>
<span id="cb55-24"><a href="#cb55-24"></a>        <span class="op">})</span>;</span>
<span id="cb55-25"><a href="#cb55-25"></a></span>
<span id="cb55-26"><a href="#cb55-26"></a>        <span class="cf">return</span> copy<span class="op">(</span>edna<span class="op">.</span>begin<span class="op">()</span>, edna<span class="op">.</span>end<span class="op">()</span>, ctx<span class="op">.</span>out<span class="op">())</span>;</span>
<span id="cb55-27"><a href="#cb55-27"></a>    <span class="op">}</span></span>
<span id="cb55-28"><a href="#cb55-28"></a><span class="op">}</span>;</span>
<span id="cb55-29"><a href="#cb55-29"></a></span>
<span id="cb55-30"><a href="#cb55-30"></a>print<span class="op">(</span><span class="st">&quot;&#39;{}&#39;</span><span class="sc">\n</span><span class="st">&quot;</span>, NoCapes<span class="op">{</span><span class="st">&quot;scathing concession&quot;</span><span class="op">})</span>; <span class="co">// prints &#39;thing onion&#39;</span></span></code></pre></div>
<p>-<em>end example</em>]</p>
</div>
</blockquote>
<p>And:</p>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb56"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb56-1"><a href="#cb56-1"></a>template&lt;class Context, class OutputIt&gt;</span>
<span id="cb56-2"><a href="#cb56-2"></a> class retargeted_format_context {</span>
<span id="cb56-3"><a href="#cb56-3"></a>   using <em>RetargetIt</em> = <em>unspecified</em>;</span>
<span id="cb56-4"><a href="#cb56-4"></a>   using <em>NewContext</em> = basic_format_context&lt;<em>RetargetIt</em>, typename Context::char_type&gt;; // exposition only</span>
<span id="cb56-5"><a href="#cb56-5"></a>   <em>NewContext</em> <em>new_context_</em>;                                                          // exposition only</span>
<span id="cb56-6"><a href="#cb56-6"></a></span>
<span id="cb56-7"><a href="#cb56-7"></a> public:</span>
<span id="cb56-8"><a href="#cb56-8"></a>   constexpr retargeted_format_context(Context&amp; ctx, OutputIt it);</span>
<span id="cb56-9"><a href="#cb56-9"></a>   retargeted_format_context(retargeted_format_context&amp;&amp;) = delete;</span>
<span id="cb56-10"><a href="#cb56-10"></a>   retargeted_format_context&amp; operator=(retargeted_format_context&amp;&amp;) = delete;</span>
<span id="cb56-11"><a href="#cb56-11"></a>   constexpr ~retargeted_format_context();</span>
<span id="cb56-12"><a href="#cb56-12"></a></span>
<span id="cb56-13"><a href="#cb56-13"></a>   constexpr <em>NewContext</em>&amp; context();</span>
<span id="cb56-14"><a href="#cb56-14"></a>   constexpr void flush();</span>
<span id="cb56-15"><a href="#cb56-15"></a> };</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">1</a></span> <code class="sourceCode cpp"><em>RetargetIt</em></code> is an implementation-defined type that models <code class="sourceCode cpp">output_iterator<span class="op">&lt;</span><span class="kw">const</span> <span class="kw">typename</span> Context<span class="op">::</span>char_type<span class="op">&amp;&gt;</span></code>.</p>
<div class="sourceCode" id="cb57"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb57-1"><a href="#cb57-1"></a><span class="kw">constexpr</span> retargeted_format_context<span class="op">(</span>Context<span class="op">&amp;</span> ctx, OutputIt it<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">2</a></span> <em>Effects</em>: Initializes <code class="sourceCode cpp"><em>new_context_</em></code> such that it holds the same formatting state as <code class="sourceCode cpp">ctx</code> and such that writing through the iterator yielded by <code class="sourceCode cpp"><em>new_context_</em><span class="op">.</span>out<span class="op">()</span></code> will write through <code class="sourceCode cpp">it</code>, possibly buffered.</p>
<div class="sourceCode" id="cb58"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb58-1"><a href="#cb58-1"></a><span class="kw">constexpr</span> <span class="op">~</span>retargeted_format_context<span class="op">()</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">3</a></span> <em>Effects</em>: Calls <code class="sourceCode cpp">flush<span class="op">()</span></code>.</p>
<div class="sourceCode" id="cb59"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb59-1"><a href="#cb59-1"></a><span class="kw">constexpr</span> <em>NewContext</em><span class="op">&amp;</span> context<span class="op">()</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">4</a></span> <em>Returns</em>: <code class="sourceCode cpp"><em>new_context_</em></code>.</p>
<div class="sourceCode" id="cb60"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb60-1"><a href="#cb60-1"></a><span class="kw">constexpr</span> <span class="dt">void</span> flush<span class="op">()</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_9" id="pnum_9">5</a></span> <em>Effects</em>: All of the possibly-buffered writes into <code class="sourceCode cpp"><em>new_context_</em><span class="op">.</span>out<span class="op">()</span></code> are written through the user-provided output iterator.</p>
</div>
</blockquote>
<h3 data-number="4.1.3" id="an-end_sentry-for-basic_parse_format_context"><span class="header-section-number">4.1.3</span> An <code class="sourceCode cpp">end_sentry</code> for <code class="sourceCode cpp">basic_parse_format_context</code><a href="#an-end_sentry-for-basic_parse_format_context" class="self-link"></a></h3>
<p>In <span>20.20.6.3 <a href="https://wg21.link/format.parse.ctx">[format.parse.ctx]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb61"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb61-1"><a href="#cb61-1"></a>namespace std {</span>
<span id="cb61-2"><a href="#cb61-2"></a>  template&lt;class charT&gt;</span>
<span id="cb61-3"><a href="#cb61-3"></a>  class basic_format_parse_context {</span>
<span id="cb61-4"><a href="#cb61-4"></a>  public:</span>
<span id="cb61-5"><a href="#cb61-5"></a>    using char_type = charT;</span>
<span id="cb61-6"><a href="#cb61-6"></a>    using const_iterator = typename basic_string_view&lt;charT&gt;::const_iterator;</span>
<span id="cb61-7"><a href="#cb61-7"></a>    using iterator = const_iterator;</span>
<span id="cb61-8"><a href="#cb61-8"></a></span>
<span id="cb61-9"><a href="#cb61-9"></a>  private:</span>
<span id="cb61-10"><a href="#cb61-10"></a>    iterator begin_;                                    // exposition only</span>
<span id="cb61-11"><a href="#cb61-11"></a>    iterator end_;                                      // exposition only</span>
<span id="cb61-12"><a href="#cb61-12"></a>    enum indexing { unknown, manual, automatic };       // exposition only</span>
<span id="cb61-13"><a href="#cb61-13"></a>    indexing indexing_;                                 // exposition only</span>
<span id="cb61-14"><a href="#cb61-14"></a>    size_t next_arg_id_;                                // exposition only</span>
<span id="cb61-15"><a href="#cb61-15"></a>    size_t num_args_;                                   // exposition only</span>
<span id="cb61-16"><a href="#cb61-16"></a></span>
<span id="cb61-17"><a href="#cb61-17"></a>  public:</span>
<span id="cb61-18"><a href="#cb61-18"></a>    constexpr explicit basic_format_parse_context(basic_string_view&lt;charT&gt; fmt,</span>
<span id="cb61-19"><a href="#cb61-19"></a>                                                  size_t num_args = 0) noexcept;</span>
<span id="cb61-20"><a href="#cb61-20"></a>    basic_format_parse_context(const basic_format_parse_context&amp;) = delete;</span>
<span id="cb61-21"><a href="#cb61-21"></a>    basic_format_parse_context&amp; operator=(const basic_format_parse_context&amp;) = delete;</span>
<span id="cb61-22"><a href="#cb61-22"></a></span>
<span id="cb61-23"><a href="#cb61-23"></a>    constexpr const_iterator begin() const noexcept;</span>
<span id="cb61-24"><a href="#cb61-24"></a>    constexpr const_iterator end() const noexcept;</span>
<span id="cb61-25"><a href="#cb61-25"></a>    constexpr void advance_to(const_iterator it);</span>
<span id="cb61-26"><a href="#cb61-26"></a></span>
<span id="cb61-27"><a href="#cb61-27"></a>    constexpr size_t next_arg_id();</span>
<span id="cb61-28"><a href="#cb61-28"></a>    constexpr void check_arg_id(size_t id);</span>
<span id="cb61-29"><a href="#cb61-29"></a></span>
<span id="cb61-30"><a href="#cb61-30"></a><span class="va">+   class end_sentry;</span></span>
<span id="cb61-31"><a href="#cb61-31"></a>  };</span>
<span id="cb61-32"><a href="#cb61-32"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>And later:</p>
<blockquote>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">1</a></span> <code class="sourceCode cpp">end_sentry</code> temporarily reduces the scope of the parse context to facilitate more complex parsing of format specifiers.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">2</a></span> [<em>Example</em>:</p>
<div class="sourceCode" id="cb62"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb62-1"><a href="#cb62-1"></a><span class="kw">struct</span> TwoInts <span class="op">{</span></span>
<span id="cb62-2"><a href="#cb62-2"></a>    <span class="dt">int</span> i;</span>
<span id="cb62-3"><a href="#cb62-3"></a>    <span class="dt">int</span> j;</span>
<span id="cb62-4"><a href="#cb62-4"></a><span class="op">}</span>;</span>
<span id="cb62-5"><a href="#cb62-5"></a></span>
<span id="cb62-6"><a href="#cb62-6"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span></span>
<span id="cb62-7"><a href="#cb62-7"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>TwoInts<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb62-8"><a href="#cb62-8"></a>    formatter<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> fmt_i;</span>
<span id="cb62-9"><a href="#cb62-9"></a>    formatter<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> fmt_j;</span>
<span id="cb62-10"><a href="#cb62-10"></a></span>
<span id="cb62-11"><a href="#cb62-11"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> ParseContext<span class="op">&gt;</span></span>
<span id="cb62-12"><a href="#cb62-12"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> parse<span class="op">(</span>ParseContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb62-13"><a href="#cb62-13"></a>        <span class="kw">auto</span> it <span class="op">=</span> find<span class="op">(</span>ctx<span class="op">.</span>begin<span class="op">()</span>, ctx<span class="op">.</span>end<span class="op">()</span>, <span class="ch">&#39;,&#39;</span><span class="op">)</span>;</span>
<span id="cb62-14"><a href="#cb62-14"></a>        <span class="cf">if</span> <span class="op">(</span>it <span class="op">==</span> ctx<span class="op">.</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb62-15"><a href="#cb62-15"></a>            <span class="cf">throw</span> format_error<span class="op">(</span><span class="st">&quot;invalid specifier&quot;</span><span class="op">)</span>;</span>
<span id="cb62-16"><a href="#cb62-16"></a>        <span class="op">}</span></span>
<span id="cb62-17"><a href="#cb62-17"></a></span>
<span id="cb62-18"><a href="#cb62-18"></a>        <span class="op">{</span></span>
<span id="cb62-19"><a href="#cb62-19"></a>            <span class="kw">typename</span> ParseContext<span class="op">::</span>end_sentry _<span class="op">(</span>ctx, it<span class="op">)</span>;</span>
<span id="cb62-20"><a href="#cb62-20"></a>            <span class="cf">if</span> <span class="op">(</span>fmt_i<span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span> <span class="op">!=</span> it<span class="op">)</span> <span class="op">{</span></span>
<span id="cb62-21"><a href="#cb62-21"></a>                <span class="cf">throw</span> format_error<span class="op">(</span><span class="st">&quot;invalid specifier&quot;</span><span class="op">)</span>;</span>
<span id="cb62-22"><a href="#cb62-22"></a>            <span class="op">}</span></span>
<span id="cb62-23"><a href="#cb62-23"></a>        <span class="op">}</span></span>
<span id="cb62-24"><a href="#cb62-24"></a></span>
<span id="cb62-25"><a href="#cb62-25"></a>        <span class="op">++</span>it;</span>
<span id="cb62-26"><a href="#cb62-26"></a>        ctx<span class="op">.</span>advance_to<span class="op">(</span>it<span class="op">)</span>;</span>
<span id="cb62-27"><a href="#cb62-27"></a>        <span class="cf">return</span> fmt_j<span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span>;</span>
<span id="cb62-28"><a href="#cb62-28"></a>    <span class="op">}</span></span>
<span id="cb62-29"><a href="#cb62-29"></a></span>
<span id="cb62-30"><a href="#cb62-30"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> FormatContext<span class="op">&gt;</span></span>
<span id="cb62-31"><a href="#cb62-31"></a>    <span class="kw">auto</span> format<span class="op">(</span>TwoInts ti, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb62-32"><a href="#cb62-32"></a>        <span class="kw">auto</span> out <span class="op">=</span> ctx<span class="op">.</span>out<span class="op">()</span>;</span>
<span id="cb62-33"><a href="#cb62-33"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;(&#39;</span>;</span>
<span id="cb62-34"><a href="#cb62-34"></a>        ctx<span class="op">.</span>advance_to<span class="op">(</span>out<span class="op">)</span>;</span>
<span id="cb62-35"><a href="#cb62-35"></a>        out <span class="op">=</span> fmt_i<span class="op">.</span>format<span class="op">(</span>ti<span class="op">.</span>i, ctx<span class="op">)</span>;</span>
<span id="cb62-36"><a href="#cb62-36"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;,&#39;</span>;</span>
<span id="cb62-37"><a href="#cb62-37"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39; &#39;</span>;</span>
<span id="cb62-38"><a href="#cb62-38"></a>        ctx<span class="op">.</span>advance_to<span class="op">(</span>out<span class="op">)</span>;</span>
<span id="cb62-39"><a href="#cb62-39"></a>        out <span class="op">=</span> fmt_j<span class="op">.</span>format<span class="op">(</span>ti<span class="op">.</span>j, ctx<span class="op">)</span>;</span>
<span id="cb62-40"><a href="#cb62-40"></a>        <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> <span class="ch">&#39;)&#39;</span>;</span>
<span id="cb62-41"><a href="#cb62-41"></a>        <span class="cf">return</span> out;</span>
<span id="cb62-42"><a href="#cb62-42"></a>    <span class="op">}</span></span>
<span id="cb62-43"><a href="#cb62-43"></a><span class="op">}</span>;</span>
<span id="cb62-44"><a href="#cb62-44"></a></span>
<span id="cb62-45"><a href="#cb62-45"></a>print<span class="op">(</span><span class="st">&quot;{:#04x,#06x}</span><span class="sc">\n</span><span class="st">&quot;</span>, TwoInts<span class="op">{</span><span class="dv">222</span>, <span class="dv">173</span><span class="op">})</span>; <span class="co">// prints (0xde, 0x00ad)</span></span></code></pre></div>
<p>-<em>end example</em>]</p>
</div>
</blockquote>
<p>And</p>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb63"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb63-1"><a href="#cb63-1"></a>template &lt;typename charT&gt;</span>
<span id="cb63-2"><a href="#cb63-2"></a>class basic_format_parse_context&lt;charT&gt;::end_sentry {</span>
<span id="cb63-3"><a href="#cb63-3"></a>    basic_format_parse_context&amp; <em>ctx</em>;   // exposition only</span>
<span id="cb63-4"><a href="#cb63-4"></a>    iterator <em>real_end</em>;                 // exposition only</span>
<span id="cb63-5"><a href="#cb63-5"></a></span>
<span id="cb63-6"><a href="#cb63-6"></a>public:</span>
<span id="cb63-7"><a href="#cb63-7"></a>    constexpr end_sentry(basic_format_parse_context&amp; ctx, iterator it);</span>
<span id="cb63-8"><a href="#cb63-8"></a>    end_sentry(end_sentry&amp;&amp;) = delete;</span>
<span id="cb63-9"><a href="#cb63-9"></a>    end_sentry&amp; operator=(end_sentry&amp;&amp;) = delete;</span>
<span id="cb63-10"><a href="#cb63-10"></a>    constexpr ~end_sentry();</span>
<span id="cb63-11"><a href="#cb63-11"></a>};</span></code></pre></div>
<div class="sourceCode" id="cb64"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb64-1"><a href="#cb64-1"></a>constexpr end_sentry(basic_format_parse_context&amp; ctx, iterator it);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">1</a></span> <em>Effects</em>: Initializes <code class="sourceCode cpp"><em>ctx</em></code> with <code class="sourceCode cpp">ctx</code> and <code class="sourceCode cpp"><em>real_end</em></code> with <code class="sourceCode cpp">ctx<span class="op">.</span>end<span class="op">()</span></code>. Assigns <code class="sourceCode cpp">it</code> to <code class="sourceCode cpp"><em>ctx</em><span class="op">.</span><em>end_</em></code>.</p>
<div class="sourceCode" id="cb65"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb65-1"><a href="#cb65-1"></a>constexpr ~end_sentry();</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">2</a></span> <em>Effects</em>: Assigns <code class="sourceCode cpp"><em>real_end</em></code> to <code class="sourceCode cpp"><em>ctx</em><span class="op">.</span><em>end_</em></code></p>
</div>
</blockquote>
<h3 data-number="4.1.4" id="formatting-for-ranges"><span class="header-section-number">4.1.4</span> Formatting for ranges<a href="#formatting-for-ranges" class="self-link"></a></h3>
<p>Add to <span>20.20.1 <a href="https://wg21.link/format.syn">[format.syn]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb66"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb66-1"><a href="#cb66-1"></a>namespace std {</span>
<span id="cb66-2"><a href="#cb66-2"></a>  // ...</span>
<span id="cb66-3"><a href="#cb66-3"></a></span>
<span id="cb66-4"><a href="#cb66-4"></a>  // [format.formatter], formatter</span>
<span id="cb66-5"><a href="#cb66-5"></a>  template&lt;class T, class charT = char&gt; struct formatter;</span>
<span id="cb66-6"><a href="#cb66-6"></a></span>
<span id="cb66-7"><a href="#cb66-7"></a><span class="va">+ // [format.range], range formatter</span></span>
<span id="cb66-8"><a href="#cb66-8"></a><span class="va">+ template&lt;class T, class charT = char&gt;</span></span>
<span id="cb66-9"><a href="#cb66-9"></a><span class="va">+   struct range_formatter;</span></span>
<span id="cb66-10"><a href="#cb66-10"></a><span class="va">+</span></span>
<span id="cb66-11"><a href="#cb66-11"></a><span class="va">+ template&lt;ranges::input_range R, class charT&gt;</span></span>
<span id="cb66-12"><a href="#cb66-12"></a><span class="va">+         requires (not same_as&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;R&gt;&gt;, R&gt;)</span></span>
<span id="cb66-13"><a href="#cb66-13"></a><span class="va">+           &amp;&amp; formattable&lt;ranges::range_reference_t&lt;R&gt;, charT&gt;</span></span>
<span id="cb66-14"><a href="#cb66-14"></a><span class="va">+   struct formatter&lt;R, charT&gt;</span></span>
<span id="cb66-15"><a href="#cb66-15"></a><span class="va">+     : range_formatter&lt;ranges::range_reference_t&lt;R&gt;, charT&gt;</span></span>
<span id="cb66-16"><a href="#cb66-16"></a><span class="va">+   { };</span></span>
<span id="cb66-17"><a href="#cb66-17"></a></span>
<span id="cb66-18"><a href="#cb66-18"></a>  // ...</span>
<span id="cb66-19"><a href="#cb66-19"></a>}</span></code></pre></div>
</div>
</blockquote>
<h3 data-number="4.1.5" id="formatting-for-pair-and-tuple"><span class="header-section-number">4.1.5</span> Formatting for <code class="sourceCode cpp">pair</code> and <code class="sourceCode cpp">tuple</code><a href="#formatting-for-pair-and-tuple" class="self-link"></a></h3>
<p>Add to <span>20.2.1 <a href="https://wg21.link/utility.syn">[utility.syn]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb67"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb67-1"><a href="#cb67-1"></a>namespace std {</span>
<span id="cb67-2"><a href="#cb67-2"></a>  // ...</span>
<span id="cb67-3"><a href="#cb67-3"></a></span>
<span id="cb67-4"><a href="#cb67-4"></a>  // [pairs], class template pair</span>
<span id="cb67-5"><a href="#cb67-5"></a>  template&lt;class T1, class T2&gt;</span>
<span id="cb67-6"><a href="#cb67-6"></a>    struct pair;</span>
<span id="cb67-7"><a href="#cb67-7"></a></span>
<span id="cb67-8"><a href="#cb67-8"></a><span class="va">+ template&lt;class charT, formattable&lt;charT&gt; T1, formattable&lt;charT&gt; T2&gt;</span></span>
<span id="cb67-9"><a href="#cb67-9"></a><span class="va">+   struct formatter&lt;pair&lt;T1, T2&gt;, charT&gt;</span></span>
<span id="cb67-10"><a href="#cb67-10"></a><span class="va">+     : tuple_formatter&lt;tuple&lt;remove_cvref_t&lt;T1&gt;, remove_cvref_t&lt;T2&gt;&gt;, charT&gt;</span></span>
<span id="cb67-11"><a href="#cb67-11"></a><span class="va">+   { };</span></span>
<span id="cb67-12"><a href="#cb67-12"></a></span>
<span id="cb67-13"><a href="#cb67-13"></a>  // ...</span>
<span id="cb67-14"><a href="#cb67-14"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Add to <span>20.5.2 <a href="https://wg21.link/tuple.syn">[tuple.syn]</a></span></p>
<blockquote>
<div>
<div class="sourceCode" id="cb68"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb68-1"><a href="#cb68-1"></a>#include &lt;compare&gt;              // see [compare.syn]</span>
<span id="cb68-2"><a href="#cb68-2"></a></span>
<span id="cb68-3"><a href="#cb68-3"></a>namespace std {</span>
<span id="cb68-4"><a href="#cb68-4"></a>  // [tuple.tuple], class template tuple</span>
<span id="cb68-5"><a href="#cb68-5"></a>  template&lt;class... Types&gt;</span>
<span id="cb68-6"><a href="#cb68-6"></a>    class tuple;</span>
<span id="cb68-7"><a href="#cb68-7"></a></span>
<span id="cb68-8"><a href="#cb68-8"></a><span class="va">+ template&lt;class charT, formattable&lt;charT&gt;... Types&gt;</span></span>
<span id="cb68-9"><a href="#cb68-9"></a><span class="va">+   struct formatter&lt;tuple&lt;Types...&gt;, charT&gt;</span></span>
<span id="cb68-10"><a href="#cb68-10"></a><span class="va">+     : tuple_formatter&lt;tuple&lt;remove_cvref_t&lt;Types&gt;...&gt;, charT&gt;</span></span>
<span id="cb68-11"><a href="#cb68-11"></a><span class="va">+   { };</span></span>
<span id="cb68-12"><a href="#cb68-12"></a></span>
<span id="cb68-13"><a href="#cb68-13"></a>  // ...</span>
<span id="cb68-14"><a href="#cb68-14"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Add to <span>20.20.1 <a href="https://wg21.link/format.syn">[format.syn]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb69"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb69-1"><a href="#cb69-1"></a>namespace std {</span>
<span id="cb69-2"><a href="#cb69-2"></a>  // ...</span>
<span id="cb69-3"><a href="#cb69-3"></a></span>
<span id="cb69-4"><a href="#cb69-4"></a>  // [format.formatter], formatter</span>
<span id="cb69-5"><a href="#cb69-5"></a>  template&lt;class T, class charT = char&gt; struct formatter;</span>
<span id="cb69-6"><a href="#cb69-6"></a></span>
<span id="cb69-7"><a href="#cb69-7"></a><span class="va">+ // [format.tuple], range formatter</span></span>
<span id="cb69-8"><a href="#cb69-8"></a><span class="va">+ template&lt;class Tuple, class charT = char&gt;</span></span>
<span id="cb69-9"><a href="#cb69-9"></a><span class="va">+   struct tuple_formatter;</span></span>
<span id="cb69-10"><a href="#cb69-10"></a></span>
<span id="cb69-11"><a href="#cb69-11"></a>  // ...</span>
<span id="cb69-12"><a href="#cb69-12"></a>}</span></code></pre></div>
</div>
</blockquote>
<h3 data-number="4.1.6" id="formatter-for-vectorboolreference"><span class="header-section-number">4.1.6</span> Formatter for <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code><a href="#formatter-for-vectorboolreference" class="self-link"></a></h3>
<p>Add to <span>22.3.6 <a href="https://wg21.link/vector.syn">[vector.syn]</a></span></p>
<blockquote>
<div>
<div class="sourceCode" id="cb70"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb70-1"><a href="#cb70-1"></a>namespace std {</span>
<span id="cb70-2"><a href="#cb70-2"></a>  // [vector], class template vector</span>
<span id="cb70-3"><a href="#cb70-3"></a>  template&lt;class T, class Allocator = allocator&lt;T&gt;&gt; class vector;</span>
<span id="cb70-4"><a href="#cb70-4"></a></span>
<span id="cb70-5"><a href="#cb70-5"></a>  // ...</span>
<span id="cb70-6"><a href="#cb70-6"></a></span>
<span id="cb70-7"><a href="#cb70-7"></a>  // [vector.bool], class vector&lt;bool&gt;</span>
<span id="cb70-8"><a href="#cb70-8"></a>  template&lt;class Allocator&gt; class vector&lt;bool, Allocator&gt;;</span>
<span id="cb70-9"><a href="#cb70-9"></a></span>
<span id="cb70-10"><a href="#cb70-10"></a><span class="va">+ template&lt;class R&gt;</span></span>
<span id="cb70-11"><a href="#cb70-11"></a><span class="va">+   inline constexpr bool <em>is-vector-bool-reference</em> = <em>see below</em>; // exposition only</span></span>
<span id="cb70-12"><a href="#cb70-12"></a></span>
<span id="cb70-13"><a href="#cb70-13"></a><span class="va">+ template&lt;class R, class charT&gt; requires <em>is-vector-bool-reference</em>&lt;R&gt;</span></span>
<span id="cb70-14"><a href="#cb70-14"></a><span class="va">+   struct formatter&lt;R, charT&gt;;</span></span></code></pre></div>
</div>
</blockquote>
<p>Add to [vector.bool] at the end:</p>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb71"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb71-1"><a href="#cb71-1"></a>template&lt;class R&gt;</span>
<span id="cb71-2"><a href="#cb71-2"></a>  inline constexpr bool <em>is-vector-bool-reference</em> = <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">8</a></span> The variable template <code class="sourceCode cpp"><em>is-vector-bool-reference</em><span class="op">&lt;</span>T<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code> if <code class="sourceCode cpp">T</code> denotes the type <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span>, Alloc<span class="op">&gt;::</span>reference</code> for some type <code class="sourceCode cpp">Alloc</code> and <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span>, Alloc<span class="op">&gt;</span></code> is not a program-defined specialization.</p>
<div class="sourceCode" id="cb72"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb72-1"><a href="#cb72-1"></a>template&lt;class R, class charT&gt; requires <em>is-vector-bool-reference</em>&lt;R&gt;</span>
<span id="cb72-2"><a href="#cb72-2"></a>  class formatter&lt;R, charT&gt; {</span>
<span id="cb72-3"><a href="#cb72-3"></a>    formatter&lt;bool, charT&gt; <em>fmt</em>;     // exposition only</span>
<span id="cb72-4"><a href="#cb72-4"></a></span>
<span id="cb72-5"><a href="#cb72-5"></a>  public:</span>
<span id="cb72-6"><a href="#cb72-6"></a>    template &lt;class ParseContext&gt;</span>
<span id="cb72-7"><a href="#cb72-7"></a>      constexpr typename ParseContext::iterator</span>
<span id="cb72-8"><a href="#cb72-8"></a>        parse(ParseContext&amp; ctx);</span>
<span id="cb72-9"><a href="#cb72-9"></a></span>
<span id="cb72-10"><a href="#cb72-10"></a>    template &lt;class FormatContext&gt;</span>
<span id="cb72-11"><a href="#cb72-11"></a>      typename FormatContext::iterator</span>
<span id="cb72-12"><a href="#cb72-12"></a>        format(const R&amp; ref, FormatContext&amp; ctx) const;</span>
<span id="cb72-13"><a href="#cb72-13"></a>  };</span></code></pre></div>
<div class="sourceCode" id="cb73"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb73-1"><a href="#cb73-1"></a>template &lt;class ParseContext&gt;</span>
<span id="cb73-2"><a href="#cb73-2"></a>  constexpr typename ParseContext::iterator</span>
<span id="cb73-3"><a href="#cb73-3"></a>    parse(ParseContext&amp; ctx);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">9</a></span> <em>Effects</em>: Equivalent to <code class="sourceCode cpp"><span class="cf">return</span> <em>fmt</em><span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span>;</code></p>
<div class="sourceCode" id="cb74"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb74-1"><a href="#cb74-1"></a>template &lt;class FormatContext&gt;</span>
<span id="cb74-2"><a href="#cb74-2"></a>  typename FormatContext::iterator</span>
<span id="cb74-3"><a href="#cb74-3"></a>    format(const R&amp; ref, FormatContext&amp; ctx) const;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">10</a></span> <em>Effects</em>: Equivalent to <code class="sourceCode cpp"><span class="cf">return</span> <em>fmt</em><span class="op">.</span>format<span class="op">(</span>ref, ctx<span class="op">)</span>;</code></p>
</div>
</blockquote>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">5</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-fmt-impl">
<p>[fmt-impl] Barry Revzin. 2021. Implementation for range formatting on top of <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code>. <br />
<a href="https://godbolt.org/z/fPs1Wxf8E">https://godbolt.org/z/fPs1Wxf8E</a></p>
</div>
<div id="ref-LWG3478">
<p>[LWG3478] Barry Revzin. views::split drops trailing empty range. <br />
<a href="https://wg21.link/lwg3478">https://wg21.link/lwg3478</a></p>
</div>
<div id="ref-LWG3636">
<p>[LWG3636] Arthur O’Dwyer. formatter<t>::format should be const-qualified. <br />
<a href="https://wg21.link/lwg3636">https://wg21.link/lwg3636</a></p>
</div>
<div id="ref-LWG3651">
<p>[LWG3651] Barry Revzin. Unspecified lifetime guarantees for the format string. <br />
<a href="https://wg21.link/lwg3651">https://wg21.link/lwg3651</a></p>
</div>
<div id="ref-P1636R2">
<p>[P1636R2] Lars Gullik Bjønnes. 2019-10-06. Formatters for library types. <br />
<a href="https://wg21.link/p1636r2">https://wg21.link/p1636r2</a></p>
</div>
<div id="ref-P2214R1">
<p>[P2214R1] Barry Revzin, Conor Hoekstra, Tim Song. 2021-09-14. A Plan for C++23 Ranges. <br />
<a href="https://wg21.link/p2214r1">https://wg21.link/p2214r1</a></p>
</div>
<div id="ref-P2216R3">
<p>[P2216R3] Victor Zverovich. 2021-02-15. std::format improvements. <br />
<a href="https://wg21.link/p2216r3">https://wg21.link/p2216r3</a></p>
</div>
<div id="ref-P2286R0">
<p>[P2286R0] Barry Revzin. 2021-01-15. Formatting Ranges. <br />
<a href="https://wg21.link/p2286r0">https://wg21.link/p2286r0</a></p>
</div>
<div id="ref-P2286R1">
<p>[P2286R1] Barry Revzin. 2021-02-19. Formatting Ranges. <br />
<a href="https://wg21.link/p2286r1">https://wg21.link/p2286r1</a></p>
</div>
<div id="ref-P2286R2">
<p>[P2286R2] Barry Revzin. 2021. Formatting Ranges. <br />
<a href="https://wg21.link/p2286r2">https://wg21.link/p2286r2</a></p>
</div>
<div id="ref-P2286R3">
<p>[P2286R3] Barry Revzin. 2021-11-17. Formatting Ranges. <br />
<a href="https://wg21.link/p2286r3">https://wg21.link/p2286r3</a></p>
</div>
<div id="ref-P2290R2">
<p>[P2290R2] Corentin Jabot. 2021-07-15. Delimited escape sequences. <br />
<a href="https://wg21.link/p2290r2">https://wg21.link/p2290r2</a></p>
</div>
<div id="ref-P2321R2">
<p>[P2321R2] Tim Song. 2021-06-11. zip. <br />
<a href="https://wg21.link/p2321r2">https://wg21.link/p2321r2</a></p>
</div>
<div id="ref-P2418R0">
<p>[P2418R0] Victor Zverovich. 2021. Add support for <code class="sourceCode cpp">std<span class="op">::</span>generator</code>-like types to <code class="sourceCode cpp">std<span class="op">::</span>format</code>. <br />
<a href="https://wg21.link/p2418r0">https://wg21.link/p2418r0</a></p>
</div>
<div id="ref-P2418R2">
<p>[P2418R2] Victor Zverovich. 2021-09-24. Add support for std::generator-like types to std::format. <br />
<a href="https://wg21.link/p2418r2">https://wg21.link/p2418r2</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
