<!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-02-19" />
  <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>P2286R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2021-02-19</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="#what-representation"><span class="toc-section-number">3.2</span> What representation?<span></span></a></li>
<li><a href="#what-additional-functionality"><span class="toc-section-number">3.3</span> What additional functionality?<span></span></a></li>
<li><a href="#what-about-format-specifiers"><span class="toc-section-number">3.4</span> What about format specifiers?<span></span></a></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="#specifying-formatters-for-ranges"><span class="toc-section-number">3.6</span> Specifying formatters for ranges<span></span></a></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></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><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;[{}]</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>[{},{&#39;y&#39;}]</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="P2214R0">[<a href="#ref-P2214R0" role="doc-biblioref">P2214R0</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="what-representation"><span class="header-section-number">3.2</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.</p>
<ol type="1">
<li>Should <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> 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> (as <code class="sourceCode cpp">fmt</code> currently does and as the type is constructed in C++) 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> (as is typical representationally outside of C++)?</li>
<li>Should <code class="sourceCode cpp">pair<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">int</span><span class="op">&gt;{</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">3</span>, <span class="dv">4</span><span class="op">}</span></code> (as the type is constructed) or as <code class="sourceCode cpp"><span class="op">(</span><span class="dv">3</span>, <span class="dv">4</span><span class="op">)</span></code> (as <code class="sourceCode cpp">fmt</code> currently does and is typical representationally outside of C++)?</li>
<li>Should <code class="sourceCode cpp"><span class="dt">char</span></code> and <code class="sourceCode cpp">string</code> in the context of ranges and tuples be printed as quoted (as <code class="sourceCode cpp">fmt</code> currently does) or unquoted (as these types are typically formatted)?</li>
</ol>
<p>What I’m proposing is 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>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> v <span class="op">=</span> <span class="op">{</span><span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span><span class="op">}</span>;</span>
<span id="cb14-2"><a href="#cb14-2"></a>std<span class="op">::</span>map<span class="op">&lt;</span>std<span class="op">::</span>string, <span class="dt">char</span><span class="op">&gt;</span> m <span class="op">=</span> <span class="op">{</span>{<span class="st">&quot;hello&quot;</span>, <span class="ch">&#39;h&#39;</span><span class="op">}</span>, <span class="op">{</span><span class="st">&quot;world&quot;</span>, <span class="ch">&#39;w&#39;</span><span class="op">}}</span>;</span>
<span id="cb14-3"><a href="#cb14-3"></a></span>
<span id="cb14-4"><a href="#cb14-4"></a>std<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;v={}. m={}</span><span class="sc">\n</span><span class="st">&quot;</span>, v, m<span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>print:</p>
<blockquote>
<div class="sourceCode" id="cb15"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb15-1"><a href="#cb15-1"></a>v=[1, 2, 3]. m=[(&quot;hello&quot;, &#39;h&#39;), (&quot;world&quot;, &#39;w&#39;)]</span></code></pre></div>
</blockquote>
<p>That is: ranges are surrounded with <code class="sourceCode cpp"><span class="op">[]</span></code>s and delimited with <code class="sourceCode cpp"><span class="st">&quot;, &quot;</span></code>. Pairs and tuples are surrounded with <code class="sourceCode cpp"><span class="op">()</span></code>s and delimited with <code class="sourceCode cpp"><span class="st">&quot;, &quot;</span></code>. Types like <code class="sourceCode cpp"><span class="dt">char</span></code>, <code class="sourceCode cpp">string</code>, and <code class="sourceCode cpp">string_view</code> are printed quoted.</p>
<p>It is more important to me that ranges and tuples are visually distinct (in this case <code class="sourceCode cpp"><span class="op">[]</span></code> vs <code class="sourceCode cpp"><span class="op">()</span></code>, but the way that <code class="sourceCode cpp">fmt</code> currently does it as <code class="sourceCode cpp"><span class="op">{}</span></code> vs <code class="sourceCode cpp"><span class="op">()</span></code> is also okay) than it would be to quote the string-y types. My rank order of the possible options for the map <code class="sourceCode cpp">m</code> above is:</p>
<table>
<tr>
<th>
Ranges
</th>
<th>
Tuples
</th>
<th>
Quoted?
</th>
<th>
Formatted Result
</th>
</td>
<tr>
<td>
<code class="sourceCode cpp"><span class="op">[]</span></code>
</td>
<td>
<code class="sourceCode cpp"><span class="op">()</span></code>
</td>
<td>
✔️
</td>
<td>
<code class="x">[(&quot;hello&quot;, &#39;h&#39;), (&quot;world&quot;, &#39;w&#39;)]</code>
</td>
</tr>
<tr>
<td>
<code class="sourceCode cpp"><span class="op">{}</span></code>
</td>
<td>
<code class="sourceCode cpp"><span class="op">()</span></code>
</td>
<td>
✔️
</td>
<td>
<code class="x">{(&quot;hello&quot;, &#39;h&#39;), (&quot;world&quot;, &#39;w&#39;)}</code>
</td>
</tr>
<tr>
<td>
<code class="sourceCode cpp"><span class="op">[]</span></code>
</td>
<td>
<code class="sourceCode cpp"><span class="op">()</span></code>
</td>
<td>
❌
</td>
<td>
<code class="x">[(hello, h), (world, w)]</code>
</td>
</tr>
<tr>
<td>
<code class="sourceCode cpp"><span class="op">{}</span></code>
</td>
<td>
<code class="sourceCode cpp"><span class="op">()</span></code>
</td>
<td>
❌
</td>
<td>
<code class="x">{(hello, h), (world, w)}</code>
</td>
</tr>
<tr>
<td>
<code class="sourceCode cpp"><span class="op">{}</span></code>
</td>
<td>
<code class="sourceCode cpp"><span class="op">{}</span></code>
</td>
<td>
❌
</td>
<td>
<code>{<b></b>{hello, h}, {world, w}}</code>
</td>
</tr>
</table>
<p>My preference for avoiding <code class="sourceCode cpp"><span class="op">{}</span></code> in the formatting is largely because it’s unlikely the results here can be used directly for copying and pasting directly into initialization anyway, so the priority is simply having visual distinction for the various cases.</p>
<p>With quoting, the question is how does the library choose if something is string-like and thus needs to be quoted. Currently, fmtlib makes this determination by checking for the presence of certain operations (<code class="sourceCode cpp">p<span class="op">-&gt;</span>length<span class="op">()</span></code>, <code class="sourceCode cpp">p<span class="op">-&gt;</span>find<span class="op">(</span><span class="ch">&#39;a&#39;</span><span class="op">)</span></code>, and <code class="sourceCode cpp">p<span class="op">-&gt;</span>data<span class="op">()</span></code>). We could instead add a variable template called <code class="sourceCode cpp">enable_formatting_as_string</code> to allow for opting into this kind of formatting.</p>
<h2 data-number="3.3" id="what-additional-functionality"><span class="header-section-number">3.3</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 format specifier for each element and a delimiter: this is <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>.</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. <code class="sourceCode cpp">fmt</code> does not provide such a mechanism, though the Rust itertools library does:</p>
<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></li>
</ol>
<p>This paper suggests the first two and encourages research into the third.</p>
<h2 data-number="3.4" id="what-about-format-specifiers"><span class="header-section-number">3.4</span> What about format specifiers?<a href="#what-about-format-specifiers" class="self-link"></a></h2>
<p>The implementation experience in <code class="sourceCode cpp">fmt</code> is that directly formatting ranges does <em>not</em> support any format specifiers, but <code class="sourceCode cpp">fmt<span class="op">::</span>join</code> supports providing a specifier per element as well as providing the delimiter and wrapping brackets.</p>
<p>We could add the same format specifier support for direct formatting of ranges as <code class="sourceCode cpp">fmt<span class="op">::</span>join</code> supports, but it doesn’t seem especially worthwhile. If you don’t care about formatting, <code class="sourceCode cpp"><span class="st">&quot;{}&quot;</span></code> is all you need. If you do care about formatting, it’s likely that you care about more than just the formatting of each individual element — you probably care about other things do. At which point, you’d likely need to use <code class="sourceCode cpp">fmt<span class="op">::</span>join</code> anyway.</p>
<p>That seems like the right mix of functionality to me.</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>There are several C++20 range adapters which are not <code class="sourceCode cpp"><span class="kw">const</span></code>-iterable. These include <code class="sourceCode cpp">views<span class="op">::</span>filter</code> and <code class="sourceCode cpp">views<span class="op">::</span>drop_while</code>. But <code class="sourceCode cpp">std<span class="op">::</span>format</code> takes its arguments by <code class="sourceCode cpp">Args <span class="kw">const</span><span class="op">&amp;...</span></code>, so how could they be printable?</p>
<p><code class="sourceCode cpp">fmt</code> handles this just fine even with its formatter specialization taking by const by converting the range <a href="https://github.com/fmtlib/fmt/blob/f8c2f8480aae17906409496ff1d3b965212330f0/include/fmt/ranges.h#L351">to a view first</a>.</p>
<p>So we can do something like:</p>
<blockquote>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1"></a><span class="kw">template</span> <span class="op">&lt;</span>range R, <span class="kw">typename</span> Char<span class="op">&gt;</span></span>
<span id="cb16-2"><a href="#cb16-2"></a><span class="kw">struct</span> formatter<span class="op">&lt;</span>R, Char<span class="op">&gt;</span></span>
<span id="cb16-3"><a href="#cb16-3"></a><span class="op">{</span></span>
<span id="cb16-4"><a href="#cb16-4"></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="cb16-5"><a href="#cb16-5"></a>    <span class="kw">auto</span> format<span class="op">(</span>R <span class="kw">const</span><span class="op">&amp;</span> rng, FormatContext<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-6"><a href="#cb16-6"></a>        <span class="kw">auto</span> values <span class="op">=</span> std<span class="op">::</span>views<span class="op">::</span>all<span class="op">(</span>rng<span class="op">)</span>;</span>
<span id="cb16-7"><a href="#cb16-7"></a>        <span class="co">// ...</span></span>
<span id="cb16-8"><a href="#cb16-8"></a>    <span class="op">}</span></span>
<span id="cb16-9"><a href="#cb16-9"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>But, this still doesn’t cover all the cases. If <code class="sourceCode cpp">R</code> is a type such that <code class="sourceCode cpp">R <span class="kw">const</span></code> is a <code class="sourceCode cpp">view</code> but <code class="sourceCode cpp">R</code> is move-only, that won’t compile. We can work around this case. But if <code class="sourceCode cpp">R</code> is a type that such that <code class="sourceCode cpp">view<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="kw">and</span> <span class="kw">not</span> range<span class="op">&lt;</span>R <span class="kw">const</span><span class="op">&gt;</span> <span class="kw">and</span> <span class="kw">not</span> copyable<span class="op">&lt;</span>R<span class="op">&gt;</span></code>, there’s really no way of getting this to work without changing the API.</p>
<p>Notably, the proposed <code class="sourceCode cpp">std<span class="op">::</span>generator<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is one such type <span class="citation" data-cites="P2168R0">[<a href="#ref-P2168R0" role="doc-biblioref">P2168R0</a>]</span></p>
<p>If we do want to support this case (and <code class="sourceCode cpp">fmt</code> does not), then we will need to change the API of <code class="sourceCode cpp">format</code> to take by forwarding reference instead of by const reference. That is, replace</p>
<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><span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb17-2"><a href="#cb17-2"></a>string format<span class="op">(</span>string_view fmt, <span class="kw">const</span> Args<span class="op">&amp;...</span> args<span class="op">)</span>;</span></code></pre></div>
<p>with:</p>
<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;</span><span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb18-2"><a href="#cb18-2"></a>string format<span class="op">(</span>string_view fmt, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span>;</span></code></pre></div>
<p>But it’s not that easy. While we would need <code class="sourceCode cpp">std<span class="op">::</span>generator<span class="op">&lt;</span>T<span class="op">&gt;</span></code> to bind to <code class="sourceCode cpp">Args<span class="op">&amp;&amp;</span></code> rather than <code class="sourceCode cpp">Args <span class="kw">const</span><span class="op">&amp;</span></code>, there are other cases which have the exact opposite problem: bit-fields need to bind to <code class="sourceCode cpp">Args <span class="kw">const</span><span class="op">&amp;</span></code> and cannot bind to <code class="sourceCode cpp">Args<span class="op">&amp;&amp;</span></code>.</p>
<p>So we can’t really change the API to support this use-case without breaking other use-cases. But there are workarounds for this case:</p>
<ul>
<li><code class="sourceCode cpp">fmt<span class="op">::</span>join</code>, which does take by forwarding reference</li>
<li><code class="sourceCode cpp">ranges<span class="op">::</span>ref_view</code> can wrap an lvalue of such a view, the resulting view would be <code class="sourceCode cpp"><span class="kw">const</span></code>-iterable.</li>
</ul>
<p>For example:</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">auto</span> ints_coro<span class="op">(</span><span class="dt">int</span> n<span class="op">)</span> <span class="op">-&gt;</span> std<span class="op">::</span>generator<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb19-2"><a href="#cb19-2"></a>    <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> n; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb19-3"><a href="#cb19-3"></a>        <span class="kw">co_yield</span> i;</span>
<span id="cb19-4"><a href="#cb19-4"></a>    <span class="op">}</span></span>
<span id="cb19-5"><a href="#cb19-5"></a><span class="op">}</span></span>
<span id="cb19-6"><a href="#cb19-6"></a></span>
<span id="cb19-7"><a href="#cb19-7"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}&quot;</span>, ints_coro<span class="op">(</span><span class="dv">10</span><span class="op">))</span>; <span class="co">// error</span></span>
<span id="cb19-8"><a href="#cb19-8"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;[{}]&quot;</span>, fmt<span class="op">::</span>join<span class="op">(</span>ints_coro<span class="op">(</span><span class="dv">10</span><span class="op">)</span>, <span class="st">&quot;, &quot;</span><span class="op">))</span>; <span class="co">// ok</span></span>
<span id="cb19-9"><a href="#cb19-9"></a></span>
<span id="cb19-10"><a href="#cb19-10"></a><span class="kw">auto</span> v <span class="op">=</span> ints_coro<span class="op">(</span><span class="dv">10</span><span class="op">)</span>;</span>
<span id="cb19-11"><a href="#cb19-11"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}&quot;</span>, std<span class="op">::</span>ranges<span class="op">::</span>ref_view<span class="op">(</span>v<span class="op">))</span>; <span class="co">// ok, if tedious</span></span>
<span id="cb19-12"><a href="#cb19-12"></a></span>
<span id="cb19-13"><a href="#cb19-13"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}&quot;</span>, ints_coro<span class="op">(</span><span class="dv">10</span><span class="op">)</span> <span class="op">|</span> ranges<span class="op">::</span>to<span class="op">&lt;</span>std<span class="op">::</span>vector<span class="op">&gt;)</span>; <span class="co">// ok, but expensive</span></span>
<span id="cb19-14"><a href="#cb19-14"></a>fmt<span class="op">::</span>print<span class="op">(</span><span class="st">&quot;{}&quot;</span>, views<span class="op">::</span>iota<span class="op">(</span><span class="dv">0</span>, <span class="dv">10</span><span class="op">))</span>; <span class="co">// ok, but harder to implement</span></span></code></pre></div>
</blockquote>
<p>You can see an example of formatting a move-only, non-<code class="sourceCode cpp"><span class="kw">const</span></code>-iterable range on compiler explorer <span class="citation" data-cites="fmt-non-const">[<a href="#ref-fmt-non-const" role="doc-biblioref">fmt-non-const</a>]</span>.</p>
<h2 data-number="3.6" id="specifying-formatters-for-ranges"><span class="header-section-number">3.6</span> Specifying formatters for ranges<a href="#specifying-formatters-for-ranges" class="self-link"></a></h2>
<p>It’s quite important that a <code class="sourceCode cpp">std<span class="op">::</span>string</code> whose value is <code class="sourceCode cpp"><span class="st">&quot;hello&quot;</span></code> gets printed as <code class="sourceCode cpp">hello</code> rather than something like <code class="sourceCode cpp"><span class="op">[</span>h, e, l, l, o<span class="op">]</span></code>.</p>
<p>This would basically fall out no matter how we approach implementing such a thing, so in of itself is not much of a concern. However, for users who have either custom containers or want to customize formatting of a standard container for their own types, they need to make sure that they can provide a specialization which is more constrained than the standard library’s for ranges. To ensure that they can do that, I think we need to be clear about the specific constraint we use when we specify this.</p>
<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 both its value and reference types are formattable) or allow formatting to fall back to constructing a <code class="sourceCode cpp">value</code> for each <code class="sourceCode cpp">reference</code> (and thus, in general, a range is formattable if at least its value is).</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>, there’s still not much distinction since it just wraps this question in <code class="sourceCode cpp">tuple</code> 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>. We might as well.</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 should add specializations of <code class="sourceCode cpp">formatter</code> for:</p>
<ul>
<li>any type that satisifies <code class="sourceCode cpp">range</code> whose <code class="sourceCode cpp">value_type</code> and <code class="sourceCode cpp">reference</code> are formattable,</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 formattable,</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 formattable,</li>
<li><code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code> (which does as <code class="sourceCode cpp"><span class="dt">bool</span></code> does).</li>
</ul>
<p>Ranges should be formatted as <code class="sourceCode cpp"><span class="op">[</span>x, y, z<span class="op">]</span></code> while tuples should be formatted as <code class="sourceCode cpp"><span class="op">(</span>a, b, c<span class="op">)</span></code>. For types that satisfy both (e.g. <code class="sourceCode cpp">std<span class="op">::</span>array</code>), they’re treated as ranges. In the context of formatting ranges, types that are string-like (e.g. <code class="sourceCode cpp"><span class="dt">char</span></code>, <code class="sourceCode cpp">string</code>, <code class="sourceCode cpp">string_view</code>) should be formatted as being quoted (with string-like being determined via variable template trait).</p>
<p>Formatting ranges does not support any additional format specifiers.</p>
<p>The standard library should also add a utility <code class="sourceCode cpp">std<span class="op">::</span>format_join</code> (or any other suitable name, knowing that <code class="sourceCode cpp">std<span class="op">::</span>views<span class="op">::</span>join</code> already exists), following in the footsteps of <code class="sourceCode cpp">fmt<span class="op">::</span>join</code>, which allows the user to provide more customization in how ranges and tuples get formatted.</p>
<p>For types like <code class="sourceCode cpp">std<span class="op">::</span>generator<span class="op">&lt;</span>T<span class="op">&gt;</span></code> (which are move-only, non-const-iterable ranges), users will have to either use <code class="sourceCode cpp">std<span class="op">::</span>format_join</code> facility or use something like <code class="sourceCode cpp">ranges<span class="op">::</span>ref_view</code> as shown earlier.</p>
<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-non-const">
<p>[fmt-non-const] Barry Revzin. 2021. Formatting a move-only non-const-iterable range. <br />
<a href="https://godbolt.org/z/149YqW">https://godbolt.org/z/149YqW</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-P2168R0">
<p>[P2168R0] Corentin Jabot, Lewis Baker. 2020-05-16. generator: A Synchronous Coroutine Generator Compatible With Ranges. <br />
<a href="https://wg21.link/p2168r0">https://wg21.link/p2168r0</a></p>
</div>
<div id="ref-P2214R0">
<p>[P2214R0] Barry Revzin, Conor Hoekstra, Tim Song. 2020-10-15. A Plan for C++23 Ranges. <br />
<a href="https://wg21.link/p2214r0">https://wg21.link/p2214r0</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>
</div>
</div>
</body>
</html>
