<!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="2022-07-15" />
  <title>Improve default container formatting</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">Improve default container formatting</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2585R1</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2022-07-15</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></li>
<li><a href="#design"><span class="toc-section-number">3</span> Design<span></span></a></li>
<li><a href="#wording"><span class="toc-section-number">4</span> Wording<span></span></a>
<ul>
<li><a href="#trait-and-regular-sequences"><span class="toc-section-number">4.1</span> Trait and Regular Sequences<span></span></a></li>
<li><a href="#maps-and-sets"><span class="toc-section-number">4.2</span> Maps and sets<span></span></a></li>
<li><a href="#strings"><span class="toc-section-number">4.3</span> Strings<span></span></a></li>
<li><a href="#feature-test-macro"><span class="toc-section-number">4.4</span> Feature-test Macro<span></span></a></li>
</ul></li>
<li><a href="#acknowledgements"><span class="toc-section-number">5</span> Acknowledgements<span></span></a></li>
<li><a href="#bibliography"><span class="toc-section-number">6</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="P2585R0">[<a href="#ref-P2585R0" role="doc-biblioref">P2585R0</a>]</span>, updated wording. Also renamed the enum class <code class="sourceCode cpp">range_format_kind</code> to <code class="sourceCode cpp">range_format</code>.</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="P2286R8">[<a href="#ref-P2286R8" role="doc-biblioref">P2286R8</a>]</span> adds support for formatting any range whose underlying type is formattable. Additionally, it adds support for different kinds of formatting that users can opt into, while also providing a default choice for associating containers that is more suited to what those containers represent.</p>
<p>For example, simply using <code class="sourceCode cpp"><span class="st">&quot;{}&quot;</span></code> as the specifier, we get the following outputs:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Expression</strong>
</div></th>
<th><div style="text-align:center">
<strong>Output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>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;&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></td>
<td><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></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">std<span class="op">::</span>set<span class="op">&lt;</span>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;&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></td>
<td><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></td>
</tr>
<tr class="odd">
<td><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></td>
<td><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></td>
</tr>
</tbody>
</table>
<p>In each case, we have a range over a pair of ints, but we have three different outputs - as appropriate for the different kinds of containers.</p>
<p>However, this distinction is a result of <span class="citation" data-cites="P2286R8">[<a href="#ref-P2286R8" role="doc-biblioref">P2286R8</a>]</span> explicitly providing formatters for all the standard library map and set containers, and applying those changes to them. This is something that users <em>can</em> do for their own containers as well, but which also means that it is something users <em>have</em> to do - if this is the behavior they want. For instance, the containers in Boost or Abseil just format like normal ranges:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Expression</strong>
</div></th>
<th><div style="text-align:center">
<strong>Output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code class="sourceCode cpp">boost<span class="op">::</span>container<span class="op">::</span>flat_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></td>
<td><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></td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">absl<span class="op">::</span>flat_hash_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></td>
<td><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></td>
</tr>
</tbody>
</table>
<p>This output isn’t <em>wrong</em>, per se. It’s just that it’s not ideal. And, sure, Abseil could certainly add the code necessary to make this happen. Which, at a bare minimum, would be:</p>
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> K, <span class="kw">class</span> V, <span class="kw">class</span><span class="op">...</span> Rest<span class="op">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>  <span class="kw">requires</span> std<span class="op">::</span>formattable<span class="op">&lt;</span><span class="kw">const</span> K, <span class="dt">char</span><span class="op">&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>        <span class="op">&amp;&amp;</span> std<span class="op">::</span>formattable<span class="op">&lt;</span><span class="kw">const</span> V, <span class="dt">char</span><span class="op">&gt;</span></span>
<span id="cb1-4"><a href="#cb1-4"></a><span class="kw">struct</span> std<span class="op">::</span>formatter<span class="op">&lt;</span>absl<span class="op">::</span>flat_hash_map<span class="op">&lt;</span>K, V, Rest<span class="op">...&gt;</span>, <span class="dt">char</span><span class="op">&gt;</span></span>
<span id="cb1-5"><a href="#cb1-5"></a>  <span class="op">:</span> std<span class="op">::</span>range_formatter<span class="op">&lt;</span>std<span class="op">::</span>pair<span class="op">&lt;</span><span class="kw">const</span> K, V<span class="op">&gt;</span>, <span class="dt">char</span><span class="op">&gt;</span></span>
<span id="cb1-6"><a href="#cb1-6"></a><span class="op">{</span></span>
<span id="cb1-7"><a href="#cb1-7"></a>  <span class="kw">constexpr</span> formatter<span class="op">()</span> <span class="op">{</span></span>
<span id="cb1-8"><a href="#cb1-8"></a>    <span class="kw">this</span><span class="op">-&gt;</span>set_brackets<span class="op">(</span><span class="st">&quot;{&quot;</span>, <span class="st">&quot;}&quot;</span><span class="op">)</span>;</span>
<span id="cb1-9"><a href="#cb1-9"></a>    <span class="kw">this</span><span class="op">-&gt;</span>underlying<span class="op">().</span>set_brackets<span class="op">({}</span>, <span class="op">{})</span>;</span>
<span id="cb1-10"><a href="#cb1-10"></a>    <span class="kw">this</span><span class="op">-&gt;</span>underlying<span class="op">().</span>set_separator<span class="op">(</span><span class="st">&quot;: &quot;</span><span class="op">)</span>;</span>
<span id="cb1-11"><a href="#cb1-11"></a>  <span class="op">}</span></span>
<span id="cb1-12"><a href="#cb1-12"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>Now, this isn’t a lot of code, nor is it especially complex. But it is writing code to do what seems like it should be the default behavior.</p>
<p>And, indeed, this is what <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> does. By default, formatting a map (whether it’s a <code class="sourceCode cpp">std<span class="op">::</span>map</code> or an <code class="sourceCode cpp">absl<span class="op">::</span>flat_hash_map</code>) does give you a string like <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> rather than <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>. <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> determines whether a type is map-like simply by checking if it has a member type named <code class="sourceCode cpp">mapped_type</code> (<a href="https://github.com/fmtlib/fmt/blob/7e4ad40171aa552d38cb99a5c181a0d7b150facc/include/fmt/ranges.h#L67-L78">here</a>). Similarly, <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code> determines whether a type is set-like if it has a member type named <code class="sourceCode cpp">key_type</code> (and it is not map-like) (<a href="https://github.com/fmtlib/fmt/blob/7e4ad40171aa552d38cb99a5c181a0d7b150facc/include/fmt/ranges.h#L80-L91">here</a>).</p>
<p>We can do something similar in the standard library.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="design"><span class="header-section-number">3</span> Design<a href="#design" class="self-link"></a></h1>
<p>There are several kinds of range formatting styles:</p>
<ul>
<li>map-like, as <code class="sourceCode cpp"><span class="op">{</span>k<sub>1</sub><span class="op">:</span> v<sub>1</sub>, k<sub>2</sub><span class="op">:</span> v<sub>2</sub><span class="op">}</span></code></li>
<li>set-like, as <code class="sourceCode cpp"><span class="op">{</span>v<sub>1</sub>, v<sub>2</sub><span class="op">}</span></code></li>
<li>regular sequence, as <code class="sourceCode cpp"><span class="op">[</span>v<sub>1</sub>, v<sub>2</sub><span class="op">]</span></code></li>
<li>string, as <code class="sourceCode cpp">abc</code></li>
<li>debug string, <code class="sourceCode cpp"><span class="st">&quot;</span><span class="sc">\n</span><span class="st">aan&quot;</span></code></li>
<li>disabled</li>
</ul>
<p>We can introduce an enum class for all of these kinds:</p>
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">enum</span> <span class="kw">class</span> range_format <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2"></a>    disabled,</span>
<span id="cb2-3"><a href="#cb2-3"></a>    map,</span>
<span id="cb2-4"><a href="#cb2-4"></a>    set,</span>
<span id="cb2-5"><a href="#cb2-5"></a>    sequence,</span>
<span id="cb2-6"><a href="#cb2-6"></a>    string,</span>
<span id="cb2-7"><a href="#cb2-7"></a>    debug_string,</span>
<span id="cb2-8"><a href="#cb2-8"></a><span class="op">}</span>;</span></code></pre></div>
</blockquote>
<p>Note that <code class="sourceCode cpp">range_format<span class="op">::</span>disabled</code> is <code class="sourceCode cpp"><span class="dv">0</span></code> so that converting to <code class="sourceCode cpp"><span class="dt">bool</span></code> checks if it’s enabled.</p>
<p>And a variable template (allowed to be specialized) to determine the right kind:</p>
<blockquote>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> R<span class="op">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> format_kind <span class="op">=</span> <em>unspecified</em>;</span>
<span id="cb3-3"><a href="#cb3-3"></a></span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="kw">template</span> <span class="op">&lt;</span>input_range R<span class="op">&gt;</span></span>
<span id="cb3-5"><a href="#cb3-5"></a><span class="kw">inline</span> <span class="kw">constexpr</span> range_format format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb3-6"><a href="#cb3-6"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">requires</span> <span class="op">{</span> <span class="kw">typename</span> R<span class="op">::</span>key_type; <span class="kw">typename</span> R<span class="op">::</span>mapped_type; <span class="op">}</span></span>
<span id="cb3-7"><a href="#cb3-7"></a>                <span class="kw">and</span> <em>is-2-tuple</em><span class="op">&lt;</span>range_reference_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;)</span> <span class="op">{</span></span>
<span id="cb3-8"><a href="#cb3-8"></a>    <span class="cf">return</span> range_format<span class="op">::</span>map;</span>
<span id="cb3-9"><a href="#cb3-9"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span><span class="kw">requires</span> <span class="op">{</span> <span class="kw">typename</span> R<span class="op">::</span>key_type; <span class="op">})</span> <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10"></a>    <span class="cf">return</span> range_format<span class="op">::</span>set;</span>
<span id="cb3-11"><a href="#cb3-11"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb3-12"><a href="#cb3-12"></a>    <span class="cf">return</span> range_format<span class="op">::</span>sequence;</span>
<span id="cb3-13"><a href="#cb3-13"></a>  <span class="op">}</span></span>
<span id="cb3-14"><a href="#cb3-14"></a><span class="op">}()</span>;</span></code></pre></div>
</blockquote>
<p><code class="sourceCode cpp">format_kind<span class="op">&lt;</span>U<span class="op">&gt;</span></code> for non-range types <code class="sourceCode cpp">U</code> is <code class="sourceCode cpp"><em>unspecified</em></code> to allow for future evolution in case we want to do this for non-range types. Fow now, it doesn’t cost anything.</p>
<p>As far as heuristics go, this is a pretty safe bet. While we’ve previously tried to do a heuristic for <code class="sourceCode cpp">view</code> and then had to walk it back a lot, here the stakes are much lower. Worst-case, we’re just talking about getting the default formatting wrong - for some definition of wrong - though we’d still format all the elements. And there probably aren’t too many range types floating around that define <code class="sourceCode cpp">key_type</code> and <code class="sourceCode cpp">mapped_type</code> but aren’t maps? Note that we’re being especially safe here by checking not just <code class="sourceCode cpp">R<span class="op">::</span>key_type</code> and <code class="sourceCode cpp">R<span class="op">::</span>mapped_type</code> but also that the reference type is a two-tuple (by which I mean that it’s either a specialization of <code class="sourceCode cpp">std<span class="op">::</span>pair</code> or a specialization of <code class="sourceCode cpp">std<span class="op">::</span>tuple</code> whose size is <code class="sourceCode cpp"><span class="dv">2</span></code>). This added check ensures that we don’t accidentally end up with an ill-formed default whereas the previous default could have worked fine (on the off chance that we have some type with a <code class="sourceCode cpp">key_type</code> and a <code class="sourceCode cpp">mapped_type</code> yet is somehow a range of <code class="sourceCode cpp"><span class="dt">int</span></code>).</p>
<p>Note that we’re deliberately not making any sort of guess about <code class="sourceCode cpp">string</code>. Not looking at convertibility to <code class="sourceCode cpp">string</code> or <code class="sourceCode cpp">string_view</code> or <code class="sourceCode cpp"><span class="dt">char</span> <span class="kw">const</span><span class="op">*</span></code> or anything of the sort. If users want some container to be formatted as a string, they can do so by explicitly specializing <code class="sourceCode cpp">format_kind</code> - which isn’t that much effort at all. The problem is that coming up with a heuristic would complicate <code class="sourceCode cpp">format_kind</code>, since we can’t just check convertibility to <code class="sourceCode cpp">string_view</code>, we have to specifically check convertibility to <code class="sourceCode cpp">basic_string_view<span class="op">&lt;</span>charT<span class="op">&gt;</span></code>, and now suddenly we have this extra <code class="sourceCode cpp">charT</code> parameter. Is it worth it? I’m not sure it is.</p>
<p>If we then change the way the standard library does formatting based on <code class="sourceCode cpp">format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span></code>, then with no additional code changes necessary, all the Boost and Abseil containers would start being formatted in the same kind of way that the standard library ones are today. That and many other user-defined associative containers.</p>
<p>Moreover, for user-defined containers, specializing a variable template is quite a bit less work than almost anything else you can do. So even for containers where the heuristic is wrong, this design offers an easier way forward to get the desired behavior.</p>
<p>While this design as-is has not been implemented, <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code>’s approach is pretty comparable.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="wording"><span class="header-section-number">4</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>This is in terms of <span class="citation" data-cites="P2286R8">[<a href="#ref-P2286R8" role="doc-biblioref">P2286R8</a>]</span>. The wording here chooses to define <code class="sourceCode cpp">formatter<span class="op">&lt;</span>R, charT<span class="op">&gt;</span></code> as inheriting from an exposition-only <code class="sourceCode cpp"><em>range-default-formatter</em><span class="op">&lt;</span>format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span>, R, charT<span class="op">&gt;</span></code> rather than a bunch of specializations for each <code class="sourceCode cpp">format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span></code> case because this allows future extensions where uses can create more constrained specializations of <code class="sourceCode cpp">formatter</code> for enabled ranges much easier.</p>
<h2 data-number="4.1" id="trait-and-regular-sequences"><span class="header-section-number">4.1</span> Trait and Regular Sequences<a href="#trait-and-regular-sequences" class="self-link"></a></h2>
<p>Change <span>22.14.1 <a href="https://wg21.link/format.syn">[format.syn]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb4"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb4-1"><a href="#cb4-1"></a>namespace std {</span>
<span id="cb4-2"><a href="#cb4-2"></a>  // ...</span>
<span id="cb4-3"><a href="#cb4-3"></a></span>
<span id="cb4-4"><a href="#cb4-4"></a>  // [format.formatter], formatter</span>
<span id="cb4-5"><a href="#cb4-5"></a>  template&lt;class T, class charT = char&gt; struct formatter;</span>
<span id="cb4-6"><a href="#cb4-6"></a></span>
<span id="cb4-7"><a href="#cb4-7"></a>  // [format.range.formatter], class template range_formatter</span>
<span id="cb4-8"><a href="#cb4-8"></a><span class="va">+ enum class range_format {</span></span>
<span id="cb4-9"><a href="#cb4-9"></a><span class="va">+   disabled,</span></span>
<span id="cb4-10"><a href="#cb4-10"></a><span class="va">+   map,</span></span>
<span id="cb4-11"><a href="#cb4-11"></a><span class="va">+   set,</span></span>
<span id="cb4-12"><a href="#cb4-12"></a><span class="va">+   sequence,</span></span>
<span id="cb4-13"><a href="#cb4-13"></a><span class="va">+   string,</span></span>
<span id="cb4-14"><a href="#cb4-14"></a><span class="va">+   debug_string</span></span>
<span id="cb4-15"><a href="#cb4-15"></a><span class="va">+ };</span></span>
<span id="cb4-16"><a href="#cb4-16"></a><span class="va">+</span></span>
<span id="cb4-17"><a href="#cb4-17"></a><span class="va">+ template&lt;class R&gt;</span></span>
<span id="cb4-18"><a href="#cb4-18"></a><span class="va">+   constexpr <em>unspecified</em> format_kind = <em>unspecified</em>;</span></span>
<span id="cb4-19"><a href="#cb4-19"></a><span class="va">+</span></span>
<span id="cb4-20"><a href="#cb4-20"></a><span class="va">+ template&lt;ranges::input_range R&gt;</span></span>
<span id="cb4-21"><a href="#cb4-21"></a><span class="va">+     requires same_as&lt;R, remove_cvref_t&lt;R&gt;&gt;</span></span>
<span id="cb4-22"><a href="#cb4-22"></a><span class="va">+   constexpr range_format format_kind&lt;R&gt; = <em>see below</em>;</span></span>
<span id="cb4-23"><a href="#cb4-23"></a></span>
<span id="cb4-24"><a href="#cb4-24"></a>  template&lt;class T, class charT = char&gt;</span>
<span id="cb4-25"><a href="#cb4-25"></a>      requires same_as&lt;remove_cvref_t&lt;T&gt;, T&gt; &amp;&amp; formattable&lt;T, charT&gt;</span>
<span id="cb4-26"><a href="#cb4-26"></a>    class range_formatter;</span>
<span id="cb4-27"><a href="#cb4-27"></a></span>
<span id="cb4-28"><a href="#cb4-28"></a><span class="va">+ template&lt;range_format K, ranges::input_range R, class charT&gt;</span></span>
<span id="cb4-29"><a href="#cb4-29"></a><span class="va">+   struct <em>range-default-formatter</em>; // exposition only</span></span>
<span id="cb4-30"><a href="#cb4-30"></a></span>
<span id="cb4-31"><a href="#cb4-31"></a>  template&lt;ranges::input_range R, class charT&gt;</span>
<span id="cb4-32"><a href="#cb4-32"></a><span class="st">-         requires (!same_as&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;R&gt;&gt;, R&gt;)</span></span>
<span id="cb4-33"><a href="#cb4-33"></a><span class="va">+         requires (format_kind&lt;R&gt; != range_format::disabled)</span></span>
<span id="cb4-34"><a href="#cb4-34"></a>                &amp;&amp; formattable&lt;ranges::range_reference_t&lt;R&gt;, charT&gt;</span>
<span id="cb4-35"><a href="#cb4-35"></a><span class="st">-   struct formatter&lt;R, charT&gt;;</span></span>
<span id="cb4-36"><a href="#cb4-36"></a><span class="va">+   struct formatter&lt;R, charT&gt; : <em>range-default-formatter</em>&lt;format_kind&lt;R&gt;, R, charT&gt; { };</span></span>
<span id="cb4-37"><a href="#cb4-37"></a></span>
<span id="cb4-38"><a href="#cb4-38"></a>  // ...</span>
<span id="cb4-39"><a href="#cb4-39"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Add to [format.range]:</p>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">template</span><span class="op">&lt;</span>ranges<span class="op">::</span>input_range R<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2"></a>    <span class="kw">requires</span> same_as<span class="op">&lt;</span>R, remove_cvref_t<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></span>
<span id="cb5-3"><a href="#cb5-3"></a>  <span class="kw">constexpr</span> range_format format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="op">=</span> <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">a</a></span> A program that instantiates the primary template of <code class="sourceCode cpp">format_kind</code> is ill-formed.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">b</a></span> For a type <code class="sourceCode cpp">R</code>, <code class="sourceCode cpp">format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span></code> is defined as follows:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">(b.1)</a></span> If <code class="sourceCode cpp">same_as<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;</span>, R<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>, <code class="sourceCode cpp">format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span></code> is <code class="sourceCode cpp">range_format<span class="op">::</span>disabled</code>. [<em>Note</em>: This prevents constraint recursion for ranges whose reference type is the same range type. For example, <code class="sourceCode cpp">std<span class="op">::</span>filesystem<span class="op">::</span>path</code> is a range of <code class="sourceCode cpp">std<span class="op">::</span>filesystem<span class="op">::</span>path</code>. <em>-end note</em> ]</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">(b.2)</a></span> Otherwise, if the <em>qualified-id</em> <code class="sourceCode cpp">R<span class="op">::</span>key_type</code> is valid and denotes a type:
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">(b.2.1)</a></span> If the <em>qualified-id</em> <code class="sourceCode cpp">R<span class="op">::</span>mapped_type</code> is valid and denotes a type, let <code class="sourceCode cpp">U</code> be <code class="sourceCode cpp">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;</span></code>. If either <code class="sourceCode cpp">U</code> is a specialization of <code class="sourceCode cpp">pair</code> or <code class="sourceCode cpp">U</code> is a specialization of <code class="sourceCode cpp">tuple</code> and <code class="sourceCode cpp">tuple_size_v<span class="op">&lt;</span>U<span class="op">&gt;</span> <span class="op">==</span> <span class="dv">2</span></code>, <code class="sourceCode cpp">format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span></code> is <code class="sourceCode cpp">range_format<span class="op">::</span>map</code>.</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">(b.2.2)</a></span> Otherwise, <code class="sourceCode cpp">format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span></code> is <code class="sourceCode cpp">range_format<span class="op">::</span>set</code>.</li>
</ul></li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">(b.3)</a></span> Otherwise, <code class="sourceCode cpp">format_kind<span class="op">&lt;</span>R<span class="op">&gt;</span></code> is <code class="sourceCode cpp">range_format<span class="op">::</span>sequence</code>.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">c</a></span> <em>Remarks</em>: Pursuant to [namespace.std], users may specialize <code class="sourceCode cpp">format_kind</code> for <em>cv</em>-unqualified program-defined types that model <code class="sourceCode cpp">ranges<span class="op">::</span>input_range</code>. Such specializations shall be usable in constant expressions ([expr.const]) and have type <code class="sourceCode cpp"><span class="kw">const</span> range_format</code>.</p>
</div>
</blockquote>
<p>And later:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb6"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb6-1"><a href="#cb6-1"></a>namespace std {</span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="st">- template&lt;ranges::input_range R, class charT&gt;</span></span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="st">-         requires (!same_as&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;R&gt;&gt;, R&gt;)</span></span>
<span id="cb6-4"><a href="#cb6-4"></a><span class="st">-           &amp;&amp; formattable&lt;ranges::range_reference_t&lt;R&gt;, charT&gt;</span></span>
<span id="cb6-5"><a href="#cb6-5"></a><span class="st">- struct formatter&lt;R, charT&gt; {</span></span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="va">+ template &lt;ranges::input_range R, class charT&gt;</span></span>
<span id="cb6-7"><a href="#cb6-7"></a><span class="va">+ struct <em>range-default-formatter</em>&lt;range_format::sequence, R, charT&gt; {</span></span>
<span id="cb6-8"><a href="#cb6-8"></a>  private:</span>
<span id="cb6-9"><a href="#cb6-9"></a>    using <em>maybe-const-r</em> = <em>fmt-maybe-const</em>&lt;R, charT&gt;;</span>
<span id="cb6-10"><a href="#cb6-10"></a>    range_formatter&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;<em>maybe-const-r</em>&gt;&gt;, charT&gt; <em>underlying_</em>; // exposition only</span>
<span id="cb6-11"><a href="#cb6-11"></a></span>
<span id="cb6-12"><a href="#cb6-12"></a>  public:</span>
<span id="cb6-13"><a href="#cb6-13"></a>    constexpr void set_separator(basic_string_view&lt;charT&gt; sep);</span>
<span id="cb6-14"><a href="#cb6-14"></a>    constexpr void set_brackets(basic_string_view&lt;charT&gt; opening, basic_string_view&lt;charT&gt; closing);</span>
<span id="cb6-15"><a href="#cb6-15"></a></span>
<span id="cb6-16"><a href="#cb6-16"></a>    template &lt;class ParseContext&gt;</span>
<span id="cb6-17"><a href="#cb6-17"></a>      constexpr typename ParseContext::iterator</span>
<span id="cb6-18"><a href="#cb6-18"></a>        parse(ParseContext&amp; ctx);</span>
<span id="cb6-19"><a href="#cb6-19"></a></span>
<span id="cb6-20"><a href="#cb6-20"></a>    template &lt;class FormatContext&gt;</span>
<span id="cb6-21"><a href="#cb6-21"></a>      typename FormatContext::iterator</span>
<span id="cb6-22"><a href="#cb6-22"></a>        format(<em>maybe-const-r</em>&amp; elems, FormatContext&amp; ctx) const;</span>
<span id="cb6-23"><a href="#cb6-23"></a>  };</span>
<span id="cb6-24"><a href="#cb6-24"></a>}</span></code></pre></div>
</div>
<div class="rm" style="color: #bf0303">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_9" id="pnum_9">13</a></span> [<em>Note</em>: The <code class="sourceCode default">(!same_as&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;R&gt;&gt;, R&gt;)</code> constraint prevents constraint recursion for ranges whose reference type is the same range type. For example, <code class="sourceCode default">std::filesystem::path</code> is a range of <code class="sourceCode default">std::filesystem::path</code>. <em>-end note</em> ]</p>
</div>
<div class="sourceCode" id="cb7"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb7-1"><a href="#cb7-1"></a>constexpr void set_separator(basic_string_view&lt;charT&gt; sep);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_10" id="pnum_10">14</a></span> <em>Effects</em>: Equivalent to <code class="sourceCode cpp"><em>underlying_</em><span class="op">.</span>set_separator<span class="op">(</span>sep<span class="op">)</span></code>;</p>
</blockquote>
<h2 data-number="4.2" id="maps-and-sets"><span class="header-section-number">4.2</span> Maps and sets<a href="#maps-and-sets" class="self-link"></a></h2>
<p>Change the wording for associative containers as follows and move into [format.range] (after the previous section), it’s currently specified by <span class="citation" data-cites="P2286R8">[<a href="#ref-P2286R8" role="doc-biblioref">P2286R8</a>]</span> to be added into a new clause [assoc.format]:</p>
<blockquote>
<div class="rm" style="color: #bf0303">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_11" id="pnum_11">1</a></span> For each of <code class="sourceCode default">map</code>, <code class="sourceCode default">multimap</code>, <code class="sourceCode default">unordered_map</code>, and <code class="sourceCode default">unordered_multimap</code>, the library provides the following formatter specialization where <code class="sourceCode default"><em>map-type</em></code> is the name of the template:</p>
</div>
<div>
<div class="sourceCode" id="cb8"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb8-1"><a href="#cb8-1"></a>namespace std {</span>
<span id="cb8-2"><a href="#cb8-2"></a><span class="st">- template &lt;class charT, class Key, formattable&lt;charT&gt; T, class... U&gt;</span></span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="st">-   requires formattable&lt;const Key, charT&gt;</span></span>
<span id="cb8-4"><a href="#cb8-4"></a><span class="st">- struct formatter&lt;<em>map-type</em>&lt;Key, T, U...&gt;, charT&gt;</span></span>
<span id="cb8-5"><a href="#cb8-5"></a><span class="va">+ template &lt;ranges::input_range R, class charT&gt;</span></span>
<span id="cb8-6"><a href="#cb8-6"></a><span class="va">+ struct <em>range-default-formatter</em>&lt;range_format::map, R, charT&gt; {</span></span>
<span id="cb8-7"><a href="#cb8-7"></a>  {</span>
<span id="cb8-8"><a href="#cb8-8"></a>  private:</span>
<span id="cb8-9"><a href="#cb8-9"></a><span class="st">-   using <em>maybe-const-map</em> = <em>fmt-maybe-const</em>&lt;<em>map-type</em>&lt;Key, T, U...&gt;, charT&gt;;                         // exposition only</span></span>
<span id="cb8-10"><a href="#cb8-10"></a><span class="st">-   range_formatter&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;<em>maybe-const-map</em>&gt;&gt;, charT&gt; <em>underlying_</em>; // exposition only</span></span>
<span id="cb8-11"><a href="#cb8-11"></a><span class="va">+   using <em>maybe-const-map</em> = <em>fmt-maybe-const</em>&lt;R, charT&gt;;                               // exposition only</span></span>
<span id="cb8-12"><a href="#cb8-12"></a><span class="va">+   using <em>element-type</em> = remove_cvref_t&lt;ranges::range_reference_t&lt;<em>maybe-const-map</em>&gt;&gt;; // exposition only</span></span>
<span id="cb8-13"><a href="#cb8-13"></a><span class="va">+   range_formatter&lt;<em>element-type</em>, charT&gt; <em>underlying_</em>;                                // exposition only</span></span>
<span id="cb8-14"><a href="#cb8-14"></a>  public:</span>
<span id="cb8-15"><a href="#cb8-15"></a>    constexpr formatter();</span>
<span id="cb8-16"><a href="#cb8-16"></a></span>
<span id="cb8-17"><a href="#cb8-17"></a>    template &lt;class ParseContext&gt;</span>
<span id="cb8-18"><a href="#cb8-18"></a>      constexpr typename ParseContext::iterator</span>
<span id="cb8-19"><a href="#cb8-19"></a>        parse(ParseContext&amp; ctx);</span>
<span id="cb8-20"><a href="#cb8-20"></a></span>
<span id="cb8-21"><a href="#cb8-21"></a>    template &lt;class FormatContext&gt;</span>
<span id="cb8-22"><a href="#cb8-22"></a>      typename FormatContext::iterator</span>
<span id="cb8-23"><a href="#cb8-23"></a>        format(<em>maybe-const-map</em>&amp; r, FormatContext&amp; ctx) const;</span>
<span id="cb8-24"><a href="#cb8-24"></a>  };</span>
<span id="cb8-25"><a href="#cb8-25"></a>}</span></code></pre></div>
</div>
<div class="sourceCode" id="cb9"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb9-1"><a href="#cb9-1"></a>constexpr formatter();</span></code></pre></div>
<div class="addu">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_12" id="pnum_12">2</a></span> <em>Mandates</em>: Either:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_13" id="pnum_13">(2.1)</a></span> <code class="sourceCode cpp"><em>element-type</em></code> is a specialization of <code class="sourceCode cpp">pair</code>, or</li>
<li><span class="marginalizedparent"><a class="marginalized" href="#pnum_14" id="pnum_14">(2.2)</a></span> <code class="sourceCode cpp"><em>element-type</em></code> is a specialization of <code class="sourceCode cpp">tuple</code> and <code class="sourceCode cpp">tuple_size_v<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">==</span> <span class="dv">2</span></code>.</li>
</ul>
</div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_15" id="pnum_15">3</a></span> <em>Effects</em>: Equivalent to:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb10-1"><a href="#cb10-1"></a><em>underlying_</em>.set_brackets(<em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;{&quot;), <em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;}&quot;));</span>
<span id="cb10-2"><a href="#cb10-2"></a><em>underlying_</em>.underlying().set_brackets({}, {});</span>
<span id="cb10-3"><a href="#cb10-3"></a><em>underlying_</em>.underlying().set_separator(<em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;: &quot;));</span></code></pre></div>
<div class="sourceCode" id="cb11"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb11-1"><a href="#cb11-1"></a>template &lt;class ParseContext&gt;</span>
<span id="cb11-2"><a href="#cb11-2"></a>  constexpr typename ParseContext::iterator</span>
<span id="cb11-3"><a href="#cb11-3"></a>    parse(ParseContext&amp; ctx);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_16" id="pnum_16">4</a></span> <em>Effects</em>: Equivalent to <code class="sourceCode cpp"><span class="cf">return</span> <em>underlying_</em><span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span>;</code></p>
<div class="sourceCode" id="cb12"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb12-1"><a href="#cb12-1"></a>template &lt;class FormatContext&gt;</span>
<span id="cb12-2"><a href="#cb12-2"></a>  typename FormatContext::iterator</span>
<span id="cb12-3"><a href="#cb12-3"></a>    format(<em>maybe-const-map</em>&amp; r, FormatContext&amp; ctx) const;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_17" id="pnum_17">5</a></span> <em>Effects</em>: Equivalent to <code class="sourceCode cpp"><span class="cf">return</span> <em>underlying_</em><span class="op">.</span>format<span class="op">(</span>r, ctx<span class="op">)</span>;</code></p>
<div class="rm" style="color: #bf0303">
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_18" id="pnum_18">6</a></span> For each of <code class="sourceCode default">set</code>, <code class="sourceCode default">multiset</code>, <code class="sourceCode default">unordered_set</code>, and <code class="sourceCode default">unordered_multiset</code>, the library provides the following formatter specialization where <code class="sourceCode default"><em>set-type</em></code> is the name of the template:</p>
</div>
<div>
<div class="sourceCode" id="cb13"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb13-1"><a href="#cb13-1"></a>namespace std {</span>
<span id="cb13-2"><a href="#cb13-2"></a><span class="st">- template &lt;class charT, class Key, class... U&gt;</span></span>
<span id="cb13-3"><a href="#cb13-3"></a><span class="st">-   requires formattable&lt;const Key, charT&gt;</span></span>
<span id="cb13-4"><a href="#cb13-4"></a><span class="st">- struct formatter&lt;<em>set-type</em>&lt;Key, U...&gt;, charT&gt;</span></span>
<span id="cb13-5"><a href="#cb13-5"></a><span class="va">+ template &lt;ranges::input_range R, class charT&gt;</span></span>
<span id="cb13-6"><a href="#cb13-6"></a><span class="va">+ struct <em>range-default-formatter</em>&lt;range_format::set, R, charT&gt; {</span></span>
<span id="cb13-7"><a href="#cb13-7"></a></span>
<span id="cb13-8"><a href="#cb13-8"></a>  {</span>
<span id="cb13-9"><a href="#cb13-9"></a>  private:</span>
<span id="cb13-10"><a href="#cb13-10"></a><span class="st">-   range_formatter&lt;Key, charT&gt; <em>underlying_</em>; // exposition only</span></span>
<span id="cb13-11"><a href="#cb13-11"></a><span class="va">+   using <em>maybe-const-set</em> = <em>fmt-maybe-const</em>&lt;R, charT&gt;;                       // exposition only</span></span>
<span id="cb13-12"><a href="#cb13-12"></a><span class="va">+   range_formatter&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;<em>maybe-const-set</em>&gt;&gt;, charT&gt; <em>underlying_</em>; // exposition only</span></span>
<span id="cb13-13"><a href="#cb13-13"></a></span>
<span id="cb13-14"><a href="#cb13-14"></a>  public:</span>
<span id="cb13-15"><a href="#cb13-15"></a>    constexpr formatter();</span>
<span id="cb13-16"><a href="#cb13-16"></a></span>
<span id="cb13-17"><a href="#cb13-17"></a>    template &lt;class ParseContext&gt;</span>
<span id="cb13-18"><a href="#cb13-18"></a>      constexpr typename ParseContext::iterator</span>
<span id="cb13-19"><a href="#cb13-19"></a>        parse(ParseContext&amp; ctx);</span>
<span id="cb13-20"><a href="#cb13-20"></a></span>
<span id="cb13-21"><a href="#cb13-21"></a>    template &lt;class FormatContext&gt;</span>
<span id="cb13-22"><a href="#cb13-22"></a>      typename FormatContext::iterator</span>
<span id="cb13-23"><a href="#cb13-23"></a><span class="st">-       format(const <em>set-type</em>&lt;Key, U...&gt;&amp; r, FormatContext&amp; ctx) const;</span></span>
<span id="cb13-24"><a href="#cb13-24"></a><span class="va">+       format(<em>maybe-const-set</em>&amp; r, FormatContext&amp; ctx) const;</span></span>
<span id="cb13-25"><a href="#cb13-25"></a>  };</span>
<span id="cb13-26"><a href="#cb13-26"></a>}</span></code></pre></div>
</div>
<div class="sourceCode" id="cb14"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb14-1"><a href="#cb14-1"></a>constexpr formatter();</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_19" id="pnum_19">7</a></span> <em>Effects</em>: Equivalent to:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb15-1"><a href="#cb15-1"></a><em>underlying_</em>.set_brackets(<em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;{&quot;), <em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;}&quot;));</span></code></pre></div>
<div class="sourceCode" id="cb16"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb16-1"><a href="#cb16-1"></a>template &lt;class ParseContext&gt;</span>
<span id="cb16-2"><a href="#cb16-2"></a>  constexpr typename ParseContext::iterator</span>
<span id="cb16-3"><a href="#cb16-3"></a>    parse(ParseContext&amp; ctx);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_20" id="pnum_20">8</a></span> <em>Effects</em>: Equivalent to <code class="sourceCode cpp"><span class="cf">return</span> <em>underlying_</em><span class="op">.</span>parse<span class="op">(</span>ctx<span class="op">)</span>;</code></p>
<div>
<div class="sourceCode" id="cb17"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb17-1"><a href="#cb17-1"></a>template &lt;class FormatContext&gt;</span>
<span id="cb17-2"><a href="#cb17-2"></a>  typename FormatContext::iterator</span>
<span id="cb17-3"><a href="#cb17-3"></a><span class="st">-   format(const <em>set-type</em>&lt;Key, U...&gt;&amp; r, FormatContext&amp; ctx) const;</span></span>
<span id="cb17-4"><a href="#cb17-4"></a><span class="va">+   format(<em>maybe-const-set</em>&amp; r, FormatContext&amp; ctx) const;</span></span></code></pre></div>
</div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_21" id="pnum_21">9</a></span> <em>Effects</em>: Equivalent to <code class="sourceCode cpp"><span class="cf">return</span> <em>underlying_</em><span class="op">.</span>format<span class="op">(</span>r, ctx<span class="op">)</span>;</code></p>
</blockquote>
<h2 data-number="4.3" id="strings"><span class="header-section-number">4.3</span> Strings<a href="#strings" class="self-link"></a></h2>
<p>Also add this partial specialization to handle string types:</p>
<blockquote>
<div class="addu">
<div class="sourceCode" id="cb18"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb18-1"><a href="#cb18-1"></a>template &lt;range_format K, ranges::input_range R, class charT&gt;</span>
<span id="cb18-2"><a href="#cb18-2"></a>  requires (K == range_format::string ||</span>
<span id="cb18-3"><a href="#cb18-3"></a>            K == range_format::debug_string)</span>
<span id="cb18-4"><a href="#cb18-4"></a>struct <em>range-default-formatter</em>&lt;K, R, charT&gt; {</span>
<span id="cb18-5"><a href="#cb18-5"></a>{</span>
<span id="cb18-6"><a href="#cb18-6"></a>private:</span>
<span id="cb18-7"><a href="#cb18-7"></a>  formatter&lt;basic_string&lt;charT&gt;, charT&gt; <em>underlying_</em>; // exposition only</span>
<span id="cb18-8"><a href="#cb18-8"></a></span>
<span id="cb18-9"><a href="#cb18-9"></a>public:</span>
<span id="cb18-10"><a href="#cb18-10"></a>  template &lt;class ParseContext&gt;</span>
<span id="cb18-11"><a href="#cb18-11"></a>    constexpr typename ParseContext::iterator</span>
<span id="cb18-12"><a href="#cb18-12"></a>      parse(ParseContext&amp; ctx);</span>
<span id="cb18-13"><a href="#cb18-13"></a></span>
<span id="cb18-14"><a href="#cb18-14"></a>  template &lt;class FormatContext&gt;</span>
<span id="cb18-15"><a href="#cb18-15"></a>    typename FormatContext::iterator</span>
<span id="cb18-16"><a href="#cb18-16"></a>      format(<em>see below</em>&amp; str, FormatContext&amp; ctx) const;</span>
<span id="cb18-17"><a href="#cb18-17"></a>};</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_22" id="pnum_22">1</a></span> <em>Mandates</em>: <code class="sourceCode cpp">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>, charT<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>.</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb19-1"><a href="#cb19-1"></a>template &lt;class ParseContext&gt;</span>
<span id="cb19-2"><a href="#cb19-2"></a>  constexpr typename ParseContext::iterator</span>
<span id="cb19-3"><a href="#cb19-3"></a>    parse(ParseContext&amp; ctx);</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_23" id="pnum_23">2</a></span> <em>Effects</em>: Equivalent to:</p>
<blockquote>
<div class="sourceCode" id="cb20"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb20-1"><a href="#cb20-1"></a>auto i = <em>underlying_</em>.parse(ctx);</span>
<span id="cb20-2"><a href="#cb20-2"></a>if constexpr (K == range_format::debug_string) {</span>
<span id="cb20-3"><a href="#cb20-3"></a>  <em>underlying_</em>.set_debug_format();</span>
<span id="cb20-4"><a href="#cb20-4"></a>}</span>
<span id="cb20-5"><a href="#cb20-5"></a>return i;</span></code></pre></div>
</blockquote>
<div class="sourceCode" id="cb21"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb21-1"><a href="#cb21-1"></a>template &lt;class FormatContext&gt;</span>
<span id="cb21-2"><a href="#cb21-2"></a>  typename FormatContext::iterator</span>
<span id="cb21-3"><a href="#cb21-3"></a>    format(<em>see below</em>&amp; r, FormatContext&amp; ctx) const;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_24" id="pnum_24">3</a></span> The type of <code class="sourceCode cpp">r</code> is <code class="sourceCode cpp"><span class="kw">const</span> R<span class="op">&amp;</span></code> if <code class="sourceCode cpp">input_range<span class="op">&lt;</span><span class="kw">const</span> R<span class="op">&gt;</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code> and <code class="sourceCode cpp">R<span class="op">&amp;</span></code> otherwise.</p>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_25" id="pnum_25">4</a></span> <em>Effects</em>: Let <code class="sourceCode cpp"><em>s</em></code> be a <code class="sourceCode cpp">basic_string<span class="op">&lt;</span>charT<span class="op">&gt;</span></code> such that <code class="sourceCode cpp">ranges<span class="op">::</span>equal<span class="op">(</span><em>s</em>, r<span class="op">)</span></code> is <code class="sourceCode cpp"><span class="kw">true</span></code>. Equivalent to: <code class="sourceCode cpp"><span class="cf">return</span> <em>underlying_</em><span class="op">.</span>format<span class="op">(</span><em>s</em>, ctx<span class="op">)</span>;</code></p>
</div>
</blockquote>
<h2 data-number="4.4" id="feature-test-macro"><span class="header-section-number">4.4</span> Feature-test Macro<a href="#feature-test-macro" class="self-link"></a></h2>
<p>This paper hopefully just gets implemented together with <span class="citation" data-cites="P2286R8">[<a href="#ref-P2286R8" role="doc-biblioref">P2286R8</a>]</span>, in which case no feature-test macro would be necessary. However, given the way the timeline works out, that paper may end up being adopted before this one - in which case it would still be necessary. If these end up being moved in different plenaries, then Bump the feature-test macro for <code class="sourceCode cpp">__cpp_lib_format</code> in <span>17.3.2 <a href="https://wg21.link/version.syn">[version.syn]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb22"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb22-1"><a href="#cb22-1"></a><span class="st">- #define __cpp_lib_format  <span class="diffdel">202110L</span> // also in &lt;format&gt;</span></span>
<span id="cb22-2"><a href="#cb22-2"></a><span class="va">+ #define __cpp_lib_format  <span class="diffins">2022XXL</span> // also in &lt;format&gt;</span></span></code></pre></div>
</div>
</blockquote>
<h1 data-number="5" style="border-bottom:1px solid #cccccc" id="acknowledgements"><span class="header-section-number">5</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<p>Thanks to Jeff Garland for initially pointing out this distinction, Tomasz Kamiński for suggesting this approach, Victor Zverovich for having more or less already implemented it, and Tim Song for everything else.</p>
<h1 data-number="6" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">6</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-P2286R8">
<p>[P2286R8] Barry Revzin. 2022-05-13. Formatting Ranges. <br />
<a href="https://wg21.link/p2286r8">https://wg21.link/p2286r8</a></p>
</div>
<div id="ref-P2585R0">
<p>[P2585R0] Barry Revzin. 2022-05-15. Improving default container formatting. <br />
<a href="https://wg21.link/p2585r0">https://wg21.link/p2585r0</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
