<!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="2024-09-12" />
  <title>constexpr std::format</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.csl-block{margin-left: 1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <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: #C9FBC9;
--diff-strongins: #acf2bd;
--diff-del: #FFC8EB;
--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); }
div.std blockquote { color: #000000; background-color: #F1F1F1;
border: 1px solid #D1D1D1;
padding-left: 0.5em; padding-right: 0.5em; }
div.std.ins blockquote {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.ins > div.example {
color: #000000; background-color: #C8FFC8;
border: 1px solid #B3EBB3;
}
div.std div.sourceCode { background-color: inherit; margin-left: 1em; }
div.std blockquote del { text-decoration: line-through;
color: #000000; background-color: var(--diff-del);
border: none; }
code del { border: 1px solid #ECB3C7; }
span.orange {
background-color: #ffa500;
}
span.yellow {
background-color: #ffff00;
}</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center"><code class="sourceCode cpp"><span class="kw">constexpr</span> std<span class="op">::</span>format</code></h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P3391R0 <a href="https://wg21.link/P3391">[Latest]</a> <a href="https://wg21.link/P3391/status">[Status]</a></td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2024-09-12</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="#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a>
<ul>
<li><a href="#floating-point" id="toc-floating-point"><span class="toc-section-number">1.1</span> Floating
Point<span></span></a></li>
<li><a href="#chrono-types" id="toc-chrono-types"><span class="toc-section-number">1.2</span> Chrono Types<span></span></a></li>
<li><a href="#other-types" id="toc-other-types"><span class="toc-section-number">1.3</span> Other Types<span></span></a></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">1.4</span> Implementation
Experience<span></span></a></li>
</ul></li>
<li><a href="#proposal" id="toc-proposal"><span class="toc-section-number">2</span> Proposal<span></span></a>
<ul>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">2.1</span> Wording<span></span></a></li>
</ul></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">3</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">1</span>
Introduction<a href="#introduction" class="self-link"></a></h1>
<p>With the adoption of <span class="citation" data-cites="P2741R3">[<a href="https://wg21.link/p2741r3" role="doc-biblioref">P2741R3</a>]</span>, <code class="sourceCode cpp"><span class="kw">static_assert</span></code> can
take a
<code class="sourceCode cpp">std<span class="op">::</span>string</code>.
And the standard library has a very convenient way of producing a
<code class="sourceCode cpp">std<span class="op">::</span>string</code>
by way of
<code class="sourceCode cpp">std<span class="op">::</span>format</code>.
Except that it’s not
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>,
so it’s not suitable for that purpose. Let’s change that.</p>
<p><code class="sourceCode cpp">std<span class="op">::</span>format</code>
is specified to use type-erasure, by way of a handle type as specified
in <span>22.14.8.1 <a href="https://wg21.link/format.arg">[format.arg]</a></span>/10:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Context<span class="op">&gt;</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> basic_format_arg<span class="op">&lt;</span>Context<span class="op">&gt;::</span>handle <span class="op">{</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> <span class="dt">void</span><span class="op">*</span> ptr_;                                           <span class="co">// exposition only</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> <span class="op">(*</span>format_<span class="op">)(</span>basic_format_parse_context<span class="op">&lt;</span>char_type<span class="op">&gt;&amp;</span>,</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>                    Context<span class="op">&amp;</span>, <span class="kw">const</span> <span class="dt">void</span><span class="op">*)</span>;                     <span class="co">// exposition only</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span> <span class="kw">explicit</span> handle<span class="op">(</span>T<span class="op">&amp;</span> val<span class="op">)</span> <span class="kw">noexcept</span>;         <span class="co">// exposition only</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> <span class="kw">class</span> basic_format_arg<span class="op">&lt;</span>Context<span class="op">&gt;</span>;                     <span class="co">// exposition only</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">public</span><span class="op">:</span></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> format<span class="op">(</span>basic_format_parse_context<span class="op">&lt;</span>char_type<span class="op">&gt;&amp;</span>, Context<span class="op">&amp;</span> ctx<span class="op">)</span> <span class="kw">const</span>;</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
</div>
<p>Such a type was unusable during constant evaluate due to the to cast
<code class="sourceCode cpp">ptr_</code> from <code class="sourceCode cpp"><span class="dt">void</span> <span class="kw">const</span><span class="op">*</span></code>
to some <code class="sourceCode cpp">T <span class="kw">const</span><span class="op">*</span></code>
in the <code class="sourceCode cpp">format_</code> function. But with
the adoption of <span class="citation" data-cites="P2738R1">[<a href="https://wg21.link/p2738r1" role="doc-biblioref">P2738R1</a>]</span>, that cast is now allowed. And,
if such <code class="sourceCode cpp">handle</code>s were constructed in
place, such construction is now allowed too with the adoption of <span class="citation" data-cites="P2747R2">[<a href="https://wg21.link/p2747r2" role="doc-biblioref">P2747R2</a>]</span>.</p>
<p>There’s really nothing that stands in the way of making
<code class="sourceCode cpp">std<span class="op">::</span>format</code>
fully
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>.</p>
<p>Except… there are two categories of types that we cannot immediately
support without further work.</p>
<h2 data-number="1.1" id="floating-point"><span class="header-section-number">1.1</span> Floating Point<a href="#floating-point" class="self-link"></a></h2>
<p>Integral and floating point types are specified to use <code class="sourceCode cpp">std<span class="op">::</span>to_chars</code>.
However, only one overload of
<code class="sourceCode cpp">to_chars</code> is currently declared
<code class="sourceCode cpp"><span class="kw">constexpr</span></code> in
<span>22.13.1 <a href="https://wg21.link/charconv.syn">[charconv.syn]</a></span>:</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> to_chars_result to_chars<span class="op">(</span><span class="dt">char</span><span class="op">*</span> first, <span class="dt">char</span><span class="op">*</span> last,           <span class="co">// freestanding</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>                                   <em>integer-type</em> value, <span class="dt">int</span> base <span class="op">=</span> <span class="dv">10</span><span class="op">)</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>to_chars_result to_chars<span class="op">(</span><span class="dt">char</span><span class="op">*</span> first, <span class="dt">char</span><span class="op">*</span> last,                     <span class="co">// freestanding</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>                         <span class="dt">bool</span> value, <span class="dt">int</span> base <span class="op">=</span> <span class="dv">10</span><span class="op">)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>to_chars_result to_chars<span class="op">(</span><span class="dt">char</span><span class="op">*</span> first, <span class="dt">char</span><span class="op">*</span> last,                     <span class="co">// freestanding-deleted</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>                         <em>floating-point-type</em> value<span class="op">)</span>;</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>to_chars_result to_chars<span class="op">(</span><span class="dt">char</span><span class="op">*</span> first, <span class="dt">char</span><span class="op">*</span> last,                     <span class="co">// freestanding-deleted</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>                         <em>floating-point-type</em> value, chars_format fmt<span class="op">)</span>;</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>to_chars_result to_chars<span class="op">(</span><span class="dt">char</span><span class="op">*</span> first, <span class="dt">char</span><span class="op">*</span> last,                     <span class="co">// freestanding-deleted</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>                         <em>floating-point-type</em> value, chars_format fmt, <span class="dt">int</span> precision<span class="op">)</span>;</span></code></pre></div>
</blockquote>
</div>
<p>That was added by <span class="citation" data-cites="P2291R3">[<a href="https://wg21.link/p2291r3" role="doc-biblioref">P2291R3</a>]</span> which explicitly noted the
difficulty of implementing floating point support. That paper was
adopted in 2021, and a lot has chanced since then (including multiple
floating point formatting algorithms). So perhaps this decision should
be revisited at some point.</p>
<h2 data-number="1.2" id="chrono-types"><span class="header-section-number">1.2</span> Chrono Types<a href="#chrono-types" class="self-link"></a></h2>
<p>The chrono types (all of them) are specified to be formatted as if by
streaming through <code class="sourceCode cpp">basic_ostringstream<span class="op">&lt;</span><span class="dt">char</span><span class="op">&gt;</span></code>
(see <span>29.12 <a href="https://wg21.link/time.format">[time.format]</a></span>) and
absolutely nothing in that type is
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>.
That won’t work without further changes — most likely by changing how
chrono type formatting works rather than by changing
<code class="sourceCode cpp">basic_ostringstream</code>.</p>
<h2 data-number="1.3" id="other-types"><span class="header-section-number">1.3</span> Other Types<a href="#other-types" class="self-link"></a></h2>
<p>There are a few other types in the standard library that have
formatters that rely on functionality that is not currently
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>:
<code class="sourceCode cpp">stacktrace_entry</code>, <code class="sourceCode cpp">filesystem<span class="op">::</span>path</code>,
and
<code class="sourceCode cpp">thread<span class="op">::</span>id</code>.
Those will remain
non-<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
formattable. Additionally, <code class="sourceCode cpp"><span class="dt">void</span> <span class="kw">const</span><span class="op">*</span></code>
cannot be formatted at compile time because it cannot be converted to an
address.</p>
<h2 data-number="1.4" id="implementation-experience"><span class="header-section-number">1.4</span> Implementation Experience<a href="#implementation-experience" class="self-link"></a></h2>
<p>The <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code>
library has supported compile-time formatting for a while, just through
a different API with the format string annotated: as <code class="sourceCode cpp">format_to<span class="op">(</span>out, FMT_COMPILE<span class="op">(</span><span class="st">&quot;x={}&quot;</span><span class="op">)</span>, x<span class="op">)</span></code>.
That implementation even supports floating point types at compile time
(<a href="https://godbolt.org/z/W13nxE9ds">example</a>), but not the
chrono types.</p>
<p>Implementing this in libstdc++ was mostly a matter of marking a lot
of functions
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
(which is easy thanks to <code class="sourceCode cpp"><span class="op">-</span>fimplicit<span class="op">-</span><span class="kw">constexpr</span></code>).
There were only two specific changes I had to make:</p>
<ol type="1">
<li><p>When assigning into the union, the current implementation <a href="https://github.com/gcc-mirror/gcc/blob/8c01976b8e34eaa2483ab37d1bd18ebc5c8ada95/libstdc%2B%2B-v3/include/std/format#L3270">does
this</a>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> _Tp<span class="op">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> <span class="op">[[</span><span class="at">__gnu__</span><span class="op">::</span><span class="at">__always_inline__</span><span class="op">]]</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">void</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> _M_set<span class="op">(</span>_Tp __v<span class="op">)</span> <span class="kw">noexcept</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> <span class="op">{</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>   <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>derived_from<span class="op">&lt;</span>_Tp, _HandleBase<span class="op">&gt;)</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>     std<span class="op">::</span>construct_at<span class="op">(&amp;</span>_M_handle, __v<span class="op">)</span>;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>   <span class="cf">else</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>     _S_get<span class="op">&lt;</span>_Tp<span class="op">&gt;(*</span><span class="kw">this</span><span class="op">)</span> <span class="op">=</span> __v;</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span></code></pre></div>
<p>In that last assignment, <code class="sourceCode cpp">_S_get<span class="op">&lt;</span>_Tp<span class="op">&gt;(*</span><span class="kw">this</span><span class="op">)</span></code>
returns the appropriate member of the
<code class="sourceCode cpp"><span class="kw">union</span></code> for
the type <code class="sourceCode cpp">_Tp</code>. That doesn’t work
during constant evaluation (although it can probably be made to) since
there’s no active member yet. So I had to change that to be a new
function invoked like <code class="sourceCode cpp">_S_set<span class="op">(*</span><span class="kw">this</span>, __v<span class="op">)</span></code>.</p></li>
<li><p>Like <code class="sourceCode cpp"><span class="op">{</span>fmt<span class="op">}</span></code>,
libstdc++ has a derived scanner type that is only constructed during
constant evaluation time and is only used for parsing. This gets
confusing when we also do formatting at compile time, because we don’t
have that compile-time scanner type, so casting down to it will fail. In
libstdc++, this is easy to fix though since there is a member pointer to
array of types that is just
<code class="sourceCode cpp"><span class="kw">nullptr</span></code> if
that scanner isn’t used — so we can check that before
downcasting.</p></li>
</ol>
<p>And with that, <a href="https://godbolt.org/z/ffbzP7eqb">this
works</a> (you can see the changes in question on line 3322 for the
changed call to <code class="sourceCode cpp">_S_set</code> and 4392 for
the check, at compile-time only, of
<code class="sourceCode cpp">_M_types</code>):</p>
<div class="std">
<blockquote>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">auto</span> F<span class="op">&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="kw">auto</span> formatted <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="kw">auto</span> array <span class="op">=</span> <span class="op">[]{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>array<span class="op">&lt;</span><span class="dt">char</span>, <span class="dv">100</span><span class="op">&gt;</span> a <span class="op">=</span> <span class="op">{}</span>;</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>        F<span class="op">(</span>a<span class="op">.</span>data<span class="op">())</span>;</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> a;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">}()</span>;</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>string_view<span class="op">(</span>array<span class="op">.</span>data<span class="op">())</span>;</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="op">}()</span>;</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>formatted<span class="op">&lt;[](</span><span class="dt">char</span><span class="op">*</span> p<span class="op">){</span>std<span class="op">::</span>format_to<span class="op">(</span>p, <span class="st">&quot;x={}&quot;</span>, <span class="dv">42</span><span class="op">)</span>;<span class="op">}&gt;</span> <span class="op">==</span> <span class="st">&quot;x=42&quot;</span><span class="op">)</span>;</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>formatted<span class="op">&lt;[](</span><span class="dt">char</span><span class="op">*</span> p<span class="op">){</span>std<span class="op">::</span>format_to<span class="op">(</span>p, <span class="st">&quot;x={:{}}&quot;</span>, <span class="dv">42</span>, <span class="dv">5</span><span class="op">)</span>;<span class="op">}&gt;</span> <span class="op">==</span> <span class="st">&quot;x=   42&quot;</span><span class="op">)</span>;</span></code></pre></div>
</blockquote>
</div>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="proposal"><span class="header-section-number">2</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>Make
<code class="sourceCode cpp">std<span class="op">::</span>format</code>
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>,
with the understanding that we will not (yet) be able to format floating
point and chrono types during constant evaluation time, nor the
locale-aware overloads. The facility is still plenty useful even if we
can’t format everything quite yet!</p>
<h2 data-number="2.1" id="wording"><span class="header-section-number">2.1</span> Wording<a href="#wording" class="self-link"></a></h2>
<p><span class="draftnote" style="color: #01796F">[ Drafting note: I’m
introducing the term “constexpr-enabled” to describe the standard
library formatters that have a
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
<code class="sourceCode cpp">format</code> function. This will include
most types, but not the floating-point or chrono types mentioned
earlier. As such, there are no changes to <span>29.12 <a href="https://wg21.link/time.format">[time.format]</a></span> here.
Also, most of the wording is simply adding
<code class="sourceCode cpp"><span class="kw">constexpr</span></code> to
a lot of places — only the synopses are shown in the diff below.
]</span>.</p>
<p>Add
<code class="sourceCode cpp"><span class="kw">constexpr</span></code> to
a lot of places in <span>22.14.1 <a href="https://wg21.link/format.syn">[format.syn]</a></span>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb5"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    // [format.context], class template basic_format_context</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class charT&gt; class basic_format_context;</span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    using format_context = basic_format_context&lt;unspecified, char&gt;;</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    using wformat_context = basic_format_context&lt;unspecified, wchar_t&gt;;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    // [format.args], class template basic_format_args</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    template&lt;class Context&gt; class basic_format_args;</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    using format_args = basic_format_args&lt;format_context&gt;;</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>    using wformat_args = basic_format_args&lt;wformat_context&gt;;</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>    // [format.fmt.string], class template basic_format_string</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>    template&lt;class charT, class... Args&gt;</span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>      struct basic_format_string;</span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>    template&lt;class charT&gt; struct <em>runtime-format-string</em> {                  // exposition only</span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>      basic_string_view&lt;charT&gt; str;                                       // exposition only</span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a><span class="st">-     <em>runtime-format-string</em>(basic_string_view&lt;charT&gt; s) noexcept : str(s) {}</span></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr <em>runtime-format-string</em>(basic_string_view&lt;charT&gt; s) noexcept : str(s) {}</span></span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>      <em>runtime-format-string</em>(const <em>runtime-format-string</em>&amp;) = delete;</span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a>      <em>runtime-format-string</em>&amp; operator=(const <em>runtime-format-string</em>&amp;) = delete;</span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a><span class="st">-   <em>runtime-format-string</em>&lt;char&gt; runtime_format(string_view fmt) noexcept { return fmt; }</span></span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true" tabindex="-1"></a><span class="st">-   <em>runtime-format-string</em>&lt;wchar_t&gt; runtime_format(wstring_view fmt) noexcept { return fmt; }</span></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true" tabindex="-1"></a><span class="va">+   constexpr <em>runtime-format-string</em>&lt;char&gt; runtime_format(string_view fmt) noexcept { return fmt; }</span></span>
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true" tabindex="-1"></a><span class="va">+   constexpr <em>runtime-format-string</em>&lt;wchar_t&gt; runtime_format(wstring_view fmt) noexcept { return fmt; }</span></span>
<span id="cb5-29"><a href="#cb5-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-30"><a href="#cb5-30" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-31"><a href="#cb5-31" aria-hidden="true" tabindex="-1"></a>      using format_string = basic_format_string&lt;char, type_identity_t&lt;Args&gt;...&gt;;</span>
<span id="cb5-32"><a href="#cb5-32" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-33"><a href="#cb5-33" aria-hidden="true" tabindex="-1"></a>      using wformat_string = basic_format_string&lt;wchar_t, type_identity_t&lt;Args&gt;...&gt;;</span>
<span id="cb5-34"><a href="#cb5-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-35"><a href="#cb5-35" aria-hidden="true" tabindex="-1"></a>    // [format.functions], formatting functions</span>
<span id="cb5-36"><a href="#cb5-36" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-37"><a href="#cb5-37" aria-hidden="true" tabindex="-1"></a><span class="st">-     string format(format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-38"><a href="#cb5-38" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr string format(format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-39"><a href="#cb5-39" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-40"><a href="#cb5-40" aria-hidden="true" tabindex="-1"></a><span class="st">-     wstring format(wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-41"><a href="#cb5-41" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr wstring format(wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-42"><a href="#cb5-42" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-43"><a href="#cb5-43" aria-hidden="true" tabindex="-1"></a>      string format(const locale&amp; loc, format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span>
<span id="cb5-44"><a href="#cb5-44" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-45"><a href="#cb5-45" aria-hidden="true" tabindex="-1"></a>      wstring format(const locale&amp; loc, wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span>
<span id="cb5-46"><a href="#cb5-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-47"><a href="#cb5-47" aria-hidden="true" tabindex="-1"></a><span class="st">-   string vformat(string_view fmt, format_args args);</span></span>
<span id="cb5-48"><a href="#cb5-48" aria-hidden="true" tabindex="-1"></a><span class="st">-   wstring vformat(wstring_view fmt, wformat_args args);</span></span>
<span id="cb5-49"><a href="#cb5-49" aria-hidden="true" tabindex="-1"></a><span class="va">+   constexpr string vformat(string_view fmt, format_args args);</span></span>
<span id="cb5-50"><a href="#cb5-50" aria-hidden="true" tabindex="-1"></a><span class="va">+   constexpr wstring vformat(wstring_view fmt, wformat_args args);</span></span>
<span id="cb5-51"><a href="#cb5-51" aria-hidden="true" tabindex="-1"></a>    string vformat(const locale&amp; loc, string_view fmt, format_args args);</span>
<span id="cb5-52"><a href="#cb5-52" aria-hidden="true" tabindex="-1"></a>    wstring vformat(const locale&amp; loc, wstring_view fmt, wformat_args args);</span>
<span id="cb5-53"><a href="#cb5-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-54"><a href="#cb5-54" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class... Args&gt;</span>
<span id="cb5-55"><a href="#cb5-55" aria-hidden="true" tabindex="-1"></a><span class="st">-     Out format_to(Out out, format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-56"><a href="#cb5-56" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr Out format_to(Out out, format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-57"><a href="#cb5-57" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class... Args&gt;</span>
<span id="cb5-58"><a href="#cb5-58" aria-hidden="true" tabindex="-1"></a><span class="st">-     Out format_to(Out out, wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-59"><a href="#cb5-59" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr Out format_to(Out out, wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-60"><a href="#cb5-60" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class... Args&gt;</span>
<span id="cb5-61"><a href="#cb5-61" aria-hidden="true" tabindex="-1"></a>      Out format_to(Out out, const locale&amp; loc, format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span>
<span id="cb5-62"><a href="#cb5-62" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class... Args&gt;</span>
<span id="cb5-63"><a href="#cb5-63" aria-hidden="true" tabindex="-1"></a>      Out format_to(Out out, const locale&amp; loc, wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span>
<span id="cb5-64"><a href="#cb5-64" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-65"><a href="#cb5-65" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out&gt;</span>
<span id="cb5-66"><a href="#cb5-66" aria-hidden="true" tabindex="-1"></a><span class="st">-     Out vformat_to(Out out, string_view fmt, format_args args);</span></span>
<span id="cb5-67"><a href="#cb5-67" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr Out vformat_to(Out out, string_view fmt, format_args args);</span></span>
<span id="cb5-68"><a href="#cb5-68" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out&gt;</span>
<span id="cb5-69"><a href="#cb5-69" aria-hidden="true" tabindex="-1"></a><span class="st">-     Out vformat_to(Out out, wstring_view fmt, wformat_args args);</span></span>
<span id="cb5-70"><a href="#cb5-70" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr Out vformat_to(Out out, wstring_view fmt, wformat_args args);</span></span>
<span id="cb5-71"><a href="#cb5-71" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out&gt;</span>
<span id="cb5-72"><a href="#cb5-72" aria-hidden="true" tabindex="-1"></a>      Out vformat_to(Out out, const locale&amp; loc, string_view fmt, format_args args);</span>
<span id="cb5-73"><a href="#cb5-73" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out&gt;</span>
<span id="cb5-74"><a href="#cb5-74" aria-hidden="true" tabindex="-1"></a>      Out vformat_to(Out out, const locale&amp; loc, wstring_view fmt, wformat_args args);</span>
<span id="cb5-75"><a href="#cb5-75" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-76"><a href="#cb5-76" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out&gt; struct format_to_n_result {</span>
<span id="cb5-77"><a href="#cb5-77" aria-hidden="true" tabindex="-1"></a>      Out out;</span>
<span id="cb5-78"><a href="#cb5-78" aria-hidden="true" tabindex="-1"></a>      iter_difference_t&lt;Out&gt; size;</span>
<span id="cb5-79"><a href="#cb5-79" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb5-80"><a href="#cb5-80" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class... Args&gt;</span>
<span id="cb5-81"><a href="#cb5-81" aria-hidden="true" tabindex="-1"></a><span class="st">-     format_to_n_result&lt;Out&gt; format_to_n(Out out, iter_difference_t&lt;Out&gt; n,</span></span>
<span id="cb5-82"><a href="#cb5-82" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr format_to_n_result&lt;Out&gt; format_to_n(Out out, iter_difference_t&lt;Out&gt; n,</span></span>
<span id="cb5-83"><a href="#cb5-83" aria-hidden="true" tabindex="-1"></a>                                          format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span>
<span id="cb5-84"><a href="#cb5-84" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class... Args&gt;</span>
<span id="cb5-85"><a href="#cb5-85" aria-hidden="true" tabindex="-1"></a><span class="st">-     format_to_n_result&lt;Out&gt; format_to_n(Out out, iter_difference_t&lt;Out&gt; n,</span></span>
<span id="cb5-86"><a href="#cb5-86" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr format_to_n_result&lt;Out&gt; format_to_n(Out out, iter_difference_t&lt;Out&gt; n,</span></span>
<span id="cb5-87"><a href="#cb5-87" aria-hidden="true" tabindex="-1"></a>                                          wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span>
<span id="cb5-88"><a href="#cb5-88" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class... Args&gt;</span>
<span id="cb5-89"><a href="#cb5-89" aria-hidden="true" tabindex="-1"></a>      format_to_n_result&lt;Out&gt; format_to_n(Out out, iter_difference_t&lt;Out&gt; n,</span>
<span id="cb5-90"><a href="#cb5-90" aria-hidden="true" tabindex="-1"></a>                                          const locale&amp; loc, format_string&lt;Args...&gt; fmt,</span>
<span id="cb5-91"><a href="#cb5-91" aria-hidden="true" tabindex="-1"></a>                                          Args&amp;&amp;... args);</span>
<span id="cb5-92"><a href="#cb5-92" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class... Args&gt;</span>
<span id="cb5-93"><a href="#cb5-93" aria-hidden="true" tabindex="-1"></a>      format_to_n_result&lt;Out&gt; format_to_n(Out out, iter_difference_t&lt;Out&gt; n,</span>
<span id="cb5-94"><a href="#cb5-94" aria-hidden="true" tabindex="-1"></a>                                          const locale&amp; loc, wformat_string&lt;Args...&gt; fmt,</span>
<span id="cb5-95"><a href="#cb5-95" aria-hidden="true" tabindex="-1"></a>                                          Args&amp;&amp;... args);</span>
<span id="cb5-96"><a href="#cb5-96" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-97"><a href="#cb5-97" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-98"><a href="#cb5-98" aria-hidden="true" tabindex="-1"></a><span class="st">-     size_t formatted_size(format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-99"><a href="#cb5-99" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr size_t formatted_size(format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-100"><a href="#cb5-100" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-101"><a href="#cb5-101" aria-hidden="true" tabindex="-1"></a><span class="st">-     size_t formatted_size(wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-102"><a href="#cb5-102" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr size_t formatted_size(wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span></span>
<span id="cb5-103"><a href="#cb5-103" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-104"><a href="#cb5-104" aria-hidden="true" tabindex="-1"></a>      size_t formatted_size(const locale&amp; loc, format_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span>
<span id="cb5-105"><a href="#cb5-105" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-106"><a href="#cb5-106" aria-hidden="true" tabindex="-1"></a>      size_t formatted_size(const locale&amp; loc, wformat_string&lt;Args...&gt; fmt, Args&amp;&amp;... args);</span>
<span id="cb5-107"><a href="#cb5-107" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-108"><a href="#cb5-108" aria-hidden="true" tabindex="-1"></a>    // [format.formatter], formatter</span>
<span id="cb5-109"><a href="#cb5-109" aria-hidden="true" tabindex="-1"></a>    template&lt;class T, class charT = char&gt; struct formatter;</span>
<span id="cb5-110"><a href="#cb5-110" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-111"><a href="#cb5-111" aria-hidden="true" tabindex="-1"></a>    // [format.formatter.locking], formatter locking</span>
<span id="cb5-112"><a href="#cb5-112" aria-hidden="true" tabindex="-1"></a>    template&lt;class T&gt;</span>
<span id="cb5-113"><a href="#cb5-113" aria-hidden="true" tabindex="-1"></a>      constexpr bool enable_nonlocking_formatter_optimization = false;</span>
<span id="cb5-114"><a href="#cb5-114" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-115"><a href="#cb5-115" aria-hidden="true" tabindex="-1"></a>    // [format.formattable], concept formattable</span>
<span id="cb5-116"><a href="#cb5-116" aria-hidden="true" tabindex="-1"></a>    template&lt;class T, class charT&gt;</span>
<span id="cb5-117"><a href="#cb5-117" aria-hidden="true" tabindex="-1"></a>      concept formattable = see below;</span>
<span id="cb5-118"><a href="#cb5-118" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-119"><a href="#cb5-119" aria-hidden="true" tabindex="-1"></a>    template&lt;class R, class charT&gt;</span>
<span id="cb5-120"><a href="#cb5-120" aria-hidden="true" tabindex="-1"></a>      concept const-formattable-range =                                   // exposition only</span>
<span id="cb5-121"><a href="#cb5-121" aria-hidden="true" tabindex="-1"></a>        ranges::input_range&lt;const R&gt; &amp;&amp;</span>
<span id="cb5-122"><a href="#cb5-122" aria-hidden="true" tabindex="-1"></a>        formattable&lt;ranges::range_reference_t&lt;const R&gt;, charT&gt;;</span>
<span id="cb5-123"><a href="#cb5-123" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-124"><a href="#cb5-124" aria-hidden="true" tabindex="-1"></a>    template&lt;class R, class charT&gt;</span>
<span id="cb5-125"><a href="#cb5-125" aria-hidden="true" tabindex="-1"></a>      using fmt-maybe-const =                                             // exposition only</span>
<span id="cb5-126"><a href="#cb5-126" aria-hidden="true" tabindex="-1"></a>        conditional_t&lt;const-formattable-range&lt;R, charT&gt;, const R, R&gt;;</span>
<span id="cb5-127"><a href="#cb5-127" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-128"><a href="#cb5-128" aria-hidden="true" tabindex="-1"></a>    // [format.parse.ctx], class template basic_format_parse_context</span>
<span id="cb5-129"><a href="#cb5-129" aria-hidden="true" tabindex="-1"></a>    template&lt;class charT&gt; class basic_format_parse_context;</span>
<span id="cb5-130"><a href="#cb5-130" aria-hidden="true" tabindex="-1"></a>    using format_parse_context = basic_format_parse_context&lt;char&gt;;</span>
<span id="cb5-131"><a href="#cb5-131" aria-hidden="true" tabindex="-1"></a>    using wformat_parse_context = basic_format_parse_context&lt;wchar_t&gt;;</span>
<span id="cb5-132"><a href="#cb5-132" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-133"><a href="#cb5-133" aria-hidden="true" tabindex="-1"></a>    // [format.range], formatting of ranges</span>
<span id="cb5-134"><a href="#cb5-134" aria-hidden="true" tabindex="-1"></a>    // [format.range.fmtkind], variable template format_kind</span>
<span id="cb5-135"><a href="#cb5-135" aria-hidden="true" tabindex="-1"></a>    enum class range_format {</span>
<span id="cb5-136"><a href="#cb5-136" aria-hidden="true" tabindex="-1"></a>      disabled,</span>
<span id="cb5-137"><a href="#cb5-137" aria-hidden="true" tabindex="-1"></a>      map,</span>
<span id="cb5-138"><a href="#cb5-138" aria-hidden="true" tabindex="-1"></a>      set,</span>
<span id="cb5-139"><a href="#cb5-139" aria-hidden="true" tabindex="-1"></a>      sequence,</span>
<span id="cb5-140"><a href="#cb5-140" aria-hidden="true" tabindex="-1"></a>      string,</span>
<span id="cb5-141"><a href="#cb5-141" aria-hidden="true" tabindex="-1"></a>      debug_string</span>
<span id="cb5-142"><a href="#cb5-142" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb5-143"><a href="#cb5-143" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-144"><a href="#cb5-144" aria-hidden="true" tabindex="-1"></a>    template&lt;class R&gt;</span>
<span id="cb5-145"><a href="#cb5-145" aria-hidden="true" tabindex="-1"></a>      constexpr unspecified format_kind = unspecified;</span>
<span id="cb5-146"><a href="#cb5-146" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-147"><a href="#cb5-147" aria-hidden="true" tabindex="-1"></a>    template&lt;ranges::input_range R&gt;</span>
<span id="cb5-148"><a href="#cb5-148" aria-hidden="true" tabindex="-1"></a>        requires same_as&lt;R, remove_cvref_t&lt;R&gt;&gt;</span>
<span id="cb5-149"><a href="#cb5-149" aria-hidden="true" tabindex="-1"></a>      constexpr range_format format_kind&lt;R&gt; = see below;</span>
<span id="cb5-150"><a href="#cb5-150" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-151"><a href="#cb5-151" aria-hidden="true" tabindex="-1"></a>    // [format.range.formatter], class template range_formatter</span>
<span id="cb5-152"><a href="#cb5-152" aria-hidden="true" tabindex="-1"></a>    template&lt;class T, class charT = char&gt;</span>
<span id="cb5-153"><a href="#cb5-153" aria-hidden="true" tabindex="-1"></a>      requires same_as&lt;remove_cvref_t&lt;T&gt;, T&gt; &amp;&amp; formattable&lt;T, charT&gt;</span>
<span id="cb5-154"><a href="#cb5-154" aria-hidden="true" tabindex="-1"></a>    class range_formatter;</span>
<span id="cb5-155"><a href="#cb5-155" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-156"><a href="#cb5-156" aria-hidden="true" tabindex="-1"></a>    // [format.range.fmtdef], class template <em>range-default-formatter</em></span>
<span id="cb5-157"><a href="#cb5-157" aria-hidden="true" tabindex="-1"></a>    template&lt;range_format K, ranges::input_range R, class charT&gt;</span>
<span id="cb5-158"><a href="#cb5-158" aria-hidden="true" tabindex="-1"></a>      struct <em>range-default-formatter</em>;                                     // exposition only</span>
<span id="cb5-159"><a href="#cb5-159" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-160"><a href="#cb5-160" aria-hidden="true" tabindex="-1"></a>    // [format.range.fmtmap], [format.range.fmtset], [format.range.fmtstr], specializations for maps, sets, and strings</span>
<span id="cb5-161"><a href="#cb5-161" aria-hidden="true" tabindex="-1"></a>    template&lt;ranges::input_range R, class charT&gt;</span>
<span id="cb5-162"><a href="#cb5-162" aria-hidden="true" tabindex="-1"></a>      requires (format_kind&lt;R&gt; != range_format::disabled) &amp;&amp;</span>
<span id="cb5-163"><a href="#cb5-163" aria-hidden="true" tabindex="-1"></a>               formattable&lt;ranges::range_reference_t&lt;R&gt;, charT&gt;</span>
<span id="cb5-164"><a href="#cb5-164" aria-hidden="true" tabindex="-1"></a>    struct formatter&lt;R, charT&gt; : <em>range-default-formatter</em>&lt;format_kind&lt;R&gt;, R, charT&gt; { };</span>
<span id="cb5-165"><a href="#cb5-165" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-166"><a href="#cb5-166" aria-hidden="true" tabindex="-1"></a>    template&lt;ranges::input_range R&gt;</span>
<span id="cb5-167"><a href="#cb5-167" aria-hidden="true" tabindex="-1"></a>        requires (format_kind&lt;R&gt; != range_format::disabled)</span>
<span id="cb5-168"><a href="#cb5-168" aria-hidden="true" tabindex="-1"></a>      inline constexpr bool enable_nonlocking_formatter_optimization&lt;R&gt; = false;</span>
<span id="cb5-169"><a href="#cb5-169" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-170"><a href="#cb5-170" aria-hidden="true" tabindex="-1"></a>    // [format.arguments], arguments</span>
<span id="cb5-171"><a href="#cb5-171" aria-hidden="true" tabindex="-1"></a>    // [format.arg], class template basic_format_arg</span>
<span id="cb5-172"><a href="#cb5-172" aria-hidden="true" tabindex="-1"></a>    template&lt;class Context&gt; class basic_format_arg;</span>
<span id="cb5-173"><a href="#cb5-173" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-174"><a href="#cb5-174" aria-hidden="true" tabindex="-1"></a>    // [format.arg.store], class template <em>format-arg-store</em></span>
<span id="cb5-175"><a href="#cb5-175" aria-hidden="true" tabindex="-1"></a>    template&lt;class Context, class... Args&gt; class <em>format-arg-store</em>;        // exposition only</span>
<span id="cb5-176"><a href="#cb5-176" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-177"><a href="#cb5-177" aria-hidden="true" tabindex="-1"></a>    template&lt;class Context = format_context, class... Args&gt;</span>
<span id="cb5-178"><a href="#cb5-178" aria-hidden="true" tabindex="-1"></a><span class="st">-     <em>format-arg-store</em>&lt;Context, Args...&gt;</span></span>
<span id="cb5-179"><a href="#cb5-179" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr <em>format-arg-store</em>&lt;Context, Args...&gt;</span></span>
<span id="cb5-180"><a href="#cb5-180" aria-hidden="true" tabindex="-1"></a>        make_format_args(Args&amp;... fmt_args);</span>
<span id="cb5-181"><a href="#cb5-181" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Args&gt;</span>
<span id="cb5-182"><a href="#cb5-182" aria-hidden="true" tabindex="-1"></a><span class="st">-     <em>format-arg-store</em>&lt;wformat_context, Args...&gt;</span></span>
<span id="cb5-183"><a href="#cb5-183" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr <em>format-arg-store</em>&lt;wformat_context, Args...&gt;</span></span>
<span id="cb5-184"><a href="#cb5-184" aria-hidden="true" tabindex="-1"></a>        make_wformat_args(Args&amp;... args);</span>
<span id="cb5-185"><a href="#cb5-185" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-186"><a href="#cb5-186" aria-hidden="true" tabindex="-1"></a>    // [format.error], class format_error</span>
<span id="cb5-187"><a href="#cb5-187" aria-hidden="true" tabindex="-1"></a>    class format_error;</span>
<span id="cb5-188"><a href="#cb5-188" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
<p>Apply the same changes where these functions are referenced.</p>
<p>Add to <span>22.14.6.4 <a href="https://wg21.link/format.formatter.spec">[format.formatter.spec]</a></span>:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_1" id="pnum_1">2</a></span>
Let <code class="sourceCode cpp">charT</code> be either
<code class="sourceCode cpp"><span class="dt">char</span></code> or
<code class="sourceCode cpp"><span class="dt">wchar_t</span></code>.
Each specialization of <code class="sourceCode cpp">formatter</code> is
either enabled or disabled, as described below. A <em>debug-enabled</em>
specialization of <code class="sourceCode cpp">formatter</code>
additionally provides a public, constexpr, non-static member function
<code class="sourceCode cpp">set_debug_format<span class="op">()</span></code>
which modifies the state of the
<code class="sourceCode cpp">formatter</code> to be as if the type of
the <code class="sourceCode cpp"><em>std-format-spec</em></code> parsed
by the last call to <code class="sourceCode cpp">parse</code> were
<code class="sourceCode cpp"><span class="op">?</span></code>. <span class="addu">A <em>constexpr-enabled</em> specialization of
<code class="sourceCode cpp">formatter</code> has its
<code class="sourceCode cpp">format</code> member function declared
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>.</span>
Each header that declares the template
<code class="sourceCode cpp">formatter</code> provides the following
enabled specializations:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_2" id="pnum_2">(2.1)</a></span>
The debug-enabled <span class="addu">and constexpr-enabled</span>
specializations</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span><span class="dt">char</span>, <span class="dt">char</span><span class="op">&gt;</span>;</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span><span class="dt">char</span>, <span class="dt">wchar_t</span><span class="op">&gt;</span>;</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span><span class="dt">wchar_t</span>, <span class="dt">wchar_t</span><span class="op">&gt;</span>;</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_3" id="pnum_3">(2.2)</a></span>
For each <code class="sourceCode cpp">charT</code>, the debug-enabled
<span class="addu">and constexpr-enabled</span> string type
specializations</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span>charT<span class="op">*</span>, charT<span class="op">&gt;</span>;</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span><span class="kw">const</span> charT<span class="op">*</span>, charT<span class="op">&gt;</span>;</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> N<span class="op">&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span>charT<span class="op">[</span>N<span class="op">]</span>, charT<span class="op">&gt;</span>;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> traits, <span class="kw">class</span> Allocator<span class="op">&gt;</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> formatter<span class="op">&lt;</span>basic_string<span class="op">&lt;</span>charT, traits, Allocator<span class="op">&gt;</span>, charT<span class="op">&gt;</span>;</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> traits<span class="op">&gt;</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> formatter<span class="op">&lt;</span>basic_string_view<span class="op">&lt;</span>charT, traits<span class="op">&gt;</span>, charT<span class="op">&gt;</span>;</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_4" id="pnum_4">(2.3)</a></span>
For each <code class="sourceCode cpp">charT</code>, for each
cv-unqualified arithmetic type
<code class="sourceCode cpp">ArithmeticT</code> other than
<code class="sourceCode cpp"><span class="dt">char</span></code>,
<code class="sourceCode cpp"><span class="dt">wchar_t</span></code>,
<code class="sourceCode cpp"><span class="dt">char8_t</span></code>,
<code class="sourceCode cpp"><span class="dt">char16_t</span></code>, or
<code class="sourceCode cpp"><span class="dt">char32_t</span></code>, a
specialization <span class="addu">that is constexpr-enabled unless
<code class="sourceCode cpp">ArithmeticT</code> is a floating-point
type</span></p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span>ArithmeticT, charT<span class="op">&gt;</span>;</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_5" id="pnum_5">(2.4)</a></span>
For each <code class="sourceCode cpp">charT</code>, the <span class="addu">constexpr-enabled</span> pointer type specialization<span class="rm" style="color: #bf0303"><del>s</del></span></p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span>nullptr_t, charT<span class="op">&gt;</span>;</span></code></pre></div></li>
<li><p><span class="marginalizedparent"><a class="marginalized" href="#pnum_6" id="pnum_6">(2.5)</a></span>
<span class="addu">For each <code class="sourceCode cpp">charT</code>,
the pointer type specializations</span></p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span><span class="dt">void</span><span class="op">*</span>, charT<span class="op">&gt;</span>;</span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span> <span class="kw">struct</span> formatter<span class="op">&lt;</span><span class="kw">const</span> <span class="dt">void</span><span class="op">*</span>, charT<span class="op">&gt;</span>;</span></code></pre></div>
<p>The parse member functions of these formatters interpret the format
specification as a
<code class="sourceCode cpp"><em>std-format-spec</em></code> as
described in [format.string.std].</p></li>
</ul>
</blockquote>
</div>
<p>Mark <code class="sourceCode cpp">basic_format_context</code> as
mostly
<code class="sourceCode cpp"><span class="kw">constexpr</span></code> in
<span>22.14.6.7 <a href="https://wg21.link/format.context">[format.context]</a></span>
(everything but
<code class="sourceCode cpp">locale<span class="op">()</span></code>,
and repeated in the specification of these functions):</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb11"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>    template&lt;class Out, class charT&gt;</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>    class basic_format_context {</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>      basic_format_args&lt;basic_format_context&gt; args_;      // exposition only</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>      Out out_;                                           // exposition only</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>      basic_format_context(const basic_format_context&amp;) = delete;</span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>      basic_format_context&amp; operator=(const basic_format_context&amp;) = delete;</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>      using iterator = Out;</span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>      using char_type = charT;</span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>      template&lt;class T&gt; using formatter_type = formatter&lt;T, charT&gt;;</span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a><span class="st">-     basic_format_arg&lt;basic_format_context&gt; arg(size_t id) const noexcept;</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr basic_format_arg&lt;basic_format_context&gt; arg(size_t id) const noexcept;</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>      std::locale locale();</span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a><span class="st">-     iterator out();</span></span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a><span class="st">-     void advance_to(iterator it);</span></span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr iterator out();</span></span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr void advance_to(iterator it);</span></span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>Mark <code class="sourceCode cpp">range_formatter<span class="op">::</span>format</code>
as <code class="sourceCode cpp"><span class="kw">constexpr</span></code>
in <span>22.14.7.2 <a href="https://wg21.link/format.range.formatter">[format.range.formatter]</a></span>
and repeated in its specification:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb12"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>    template&lt;class T, class charT = char&gt;</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>      requires same_as&lt;remove_cvref_t&lt;T&gt;, T&gt; &amp;&amp; formattable&lt;T, charT&gt;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    class range_formatter {</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>      formatter&lt;T, charT&gt; <em>underlying_</em>;                                          // exposition only</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>      basic_string_view&lt;charT&gt; <em>separator_</em> = <em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;, &quot;);      // exposition only</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>      basic_string_view&lt;charT&gt; <em>opening-bracket_</em> = <em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;[&quot;); // exposition only</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>      basic_string_view&lt;charT&gt; <em>closing-bracket_</em> = <em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;]&quot;); // exposition only</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>      constexpr void set_separator(basic_string_view&lt;charT&gt; sep) noexcept;</span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>      constexpr void set_brackets(basic_string_view&lt;charT&gt; opening,</span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>                                  basic_string_view&lt;charT&gt; closing) noexcept;</span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>      constexpr formatter&lt;T, charT&gt;&amp; underlying() noexcept { return underlying_; }</span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>      constexpr const formatter&lt;T, charT&gt;&amp; underlying() const noexcept { return underlying_; }</span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a>      template&lt;class ParseContext&gt;</span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a>        constexpr typename ParseContext::iterator</span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a>          parse(ParseContext&amp; ctx);</span>
<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a>      template&lt;ranges::input_range R, class FormatContext&gt;</span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a>          requires formattable&lt;ranges::range_reference_t&lt;R&gt;, charT&gt; &amp;&amp;</span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a>                   same_as&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;R&gt;&gt;, T&gt;</span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a><span class="st">-       typename FormatContext::iterator</span></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr typename FormatContext::iterator</span></span>
<span id="cb12-26"><a href="#cb12-26" aria-hidden="true" tabindex="-1"></a>          format(R&amp;&amp; r, FormatContext&amp; ctx) const;</span>
<span id="cb12-27"><a href="#cb12-27" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb12-28"><a href="#cb12-28" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>And likewise with
<code class="sourceCode cpp"><em>range-default-formatter</em></code> in
<span>22.14.7.3 <a href="https://wg21.link/format.range.fmtdef">[format.range.fmtdef]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb13"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>    template&lt;ranges::input_range R, class charT&gt;</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    struct <em>range-default-formatter</em>&lt;range_format::sequence, R, charT&gt; {    // exposition only</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>      using <em>maybe-const-r</em> = <em>fmt-maybe-const</em>&lt;R, charT&gt;;                    // exposition only</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>      range_formatter&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;<em>maybe-const-r</em>&gt;&gt;,</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>                      charT&gt; <em>underlying_</em>;                                 // exposition only</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>      constexpr void set_separator(basic_string_view&lt;charT&gt; sep) noexcept;</span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a>      constexpr void set_brackets(basic_string_view&lt;charT&gt; opening,</span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>                                  basic_string_view&lt;charT&gt; closing) noexcept;</span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>      template&lt;class ParseContext&gt;</span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>        constexpr typename ParseContext::iterator</span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a>          parse(ParseContext&amp; ctx);</span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a>      template&lt;class FormatContext&gt;</span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a><span class="st">-       typename FormatContext::iterator</span></span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr typename FormatContext::iterator</span></span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a>          format(<em>maybe-const-r</em>&amp; elems, FormatContext&amp; ctx) const;</span>
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>And the
<code class="sourceCode cpp"><em>range-default-formatter</em></code> for
maps in <span>22.14.7.4 <a href="https://wg21.link/format.range.fmtmap">[format.range.fmtmap]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb14"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>    template&lt;ranges::input_range R, class charT&gt;</span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    struct <em>range-default-formatter</em>&lt;range_format::map, R, charT&gt; {</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>      using <em>maybe-const-map</em> = <em>fmt-maybe-const</em>&lt;R, charT&gt;;                  // exposition only</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>      using <em>element-type</em> =                                                // exposition only</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>        remove_cvref_t&lt;ranges::range_reference_t&lt;<em>maybe-const-map</em>&gt;&gt;;</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>      range_formatter&lt;<em>element-type</em>, charT&gt; <em>underlying_</em>;                   // exposition only</span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>      constexpr range-default-formatter();</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>      template&lt;class ParseContext&gt;</span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a>        constexpr typename ParseContext::iterator</span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a>          parse(ParseContext&amp; ctx);</span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a>      template&lt;class FormatContext&gt;</span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a><span class="st">-       typename FormatContext::iterator</span></span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr typename FormatContext::iterator</span></span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a>          format(<em>maybe-const-map</em>&amp; r, FormatContext&amp; ctx) const;</span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>And the
<code class="sourceCode cpp"><em>range-default-formatter</em></code> for
sets in <span>22.14.7.5 <a href="https://wg21.link/format.range.fmtset">[format.range.fmtset]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb15"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    template&lt;ranges::input_range R, class charT&gt;</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    struct <em>range-default-formatter</em>&lt;range_format::set, R, charT&gt; {</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>      using <em>maybe-const-set</em> = <em>fmt-maybe-const</em>&lt;R, charT&gt;;                  // exposition only</span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a>      range_formatter&lt;remove_cvref_t&lt;ranges::range_reference_t&lt;<em>maybe-const-set</em>&gt;&gt;,</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>                      charT&gt; <em>underlying_</em>;                                 // exposition only</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>      constexpr <em>range-default-formatter</em>();</span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a>      template&lt;class ParseContext&gt;</span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a>        constexpr typename ParseContext::iterator</span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a>          parse(ParseContext&amp; ctx);</span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a>      template&lt;class FormatContext&gt;</span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a><span class="st">-       typename FormatContext::iterator</span></span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr typename FormatContext::iterator</span></span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a>          format(<em>maybe-const-set</em>&amp; r, FormatContext&amp; ctx) const;</span>
<span id="cb15-20"><a href="#cb15-20" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb15-21"><a href="#cb15-21" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>And the
<code class="sourceCode cpp"><em>range-default-formatter</em></code> for
strings in <span>22.14.7.6 <a href="https://wg21.link/format.range.fmtstr">[format.range.fmtstr]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb16"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>    template&lt;range_format K, ranges::input_range R, class charT&gt;</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>      requires (K == range_format::string || K == range_format::debug_string)</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>    struct <em>range-default-formatter</em>&lt;K, R, charT&gt; {</span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>      formatter&lt;basic_string&lt;charT&gt;, charT&gt; <em>underlying_</em>;                  // exposition only</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a>      template&lt;class ParseContext&gt;</span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a>        constexpr typename ParseContext::iterator</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>          parse(ParseContext&amp; ctx);</span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a>      template&lt;class FormatContext&gt;</span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a><span class="st">-       typename FormatContext::iterator</span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr typename FormatContext::iterator</span></span>
<span id="cb16-16"><a href="#cb16-16" aria-hidden="true" tabindex="-1"></a>          format(see below&amp; str, FormatContext&amp; ctx) const;</span>
<span id="cb16-17"><a href="#cb16-17" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb16-18"><a href="#cb16-18" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>The <code class="sourceCode cpp">basic_format_arg</code> class
template can be made entirely
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
too, in <span>22.14.8.1 <a href="https://wg21.link/format.arg">[format.arg]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb17"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>    template&lt;class Context&gt;</span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    class basic_format_arg {</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a>      class handle;</span>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a>      using char_type = typename Context::char_type;                              // exposition only</span>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>      variant&lt;monostate, bool, char_type,</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>              int, unsigned int, long long int, unsigned long long int,</span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>              float, double, long double,</span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>              const char_type*, basic_string_view&lt;char_type&gt;,</span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>              const void*, handle&gt; value;                                         // exposition only</span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a><span class="st">-     template&lt;class T&gt; explicit basic_format_arg(T&amp; v) noexcept;                 // exposition only</span></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a><span class="va">+     template&lt;class T&gt; constexpr explicit basic_format_arg(T&amp; v) noexcept;       // exposition only</span></span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a><span class="st">-     basic_format_arg() noexcept;</span></span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr basic_format_arg() noexcept;</span></span>
<span id="cb17-22"><a href="#cb17-22" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-23"><a href="#cb17-23" aria-hidden="true" tabindex="-1"></a><span class="st">-     explicit operator bool() const noexcept;</span></span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr explicit operator bool() const noexcept;</span></span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true" tabindex="-1"></a>      template&lt;class Visitor&gt;</span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true" tabindex="-1"></a><span class="st">-       decltype(auto) visit(this basic_format_arg arg, Visitor&amp;&amp; vis);</span></span>
<span id="cb17-28"><a href="#cb17-28" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr decltype(auto) visit(this basic_format_arg arg, Visitor&amp;&amp; vis);</span></span>
<span id="cb17-29"><a href="#cb17-29" aria-hidden="true" tabindex="-1"></a>      template&lt;class R, class Visitor&gt;</span>
<span id="cb17-30"><a href="#cb17-30" aria-hidden="true" tabindex="-1"></a><span class="st">-       R visit(this basic_format_arg arg, Visitor&amp;&amp; vis);</span></span>
<span id="cb17-31"><a href="#cb17-31" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr R visit(this basic_format_arg arg, Visitor&amp;&amp; vis);</span></span>
<span id="cb17-32"><a href="#cb17-32" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb17-33"><a href="#cb17-33" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>And the <code class="sourceCode cpp">handle</code> type introduced in
<span>22.14.8.1 <a href="https://wg21.link/format.arg">[format.arg]</a></span>/10:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_7" id="pnum_7">10</a></span>
The class handle allows formatting an object of a user-defined type.</p>
<div>
<div class="sourceCode" id="cb18"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>    template&lt;class Context&gt;</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>    class basic_format_arg&lt;Context&gt;::handle {</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>      const void* ptr_;                                           // exposition only</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>      void (*format_)(basic_format_parse_context&lt;char_type&gt;&amp;,</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>                      Context&amp;, const void*);                     // exposition only</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="st">-     template&lt;class T&gt; explicit handle(T&amp; val) noexcept;         // exposition only</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a><span class="va">+     template&lt;class T&gt; constexpr explicit handle(T&amp; val) noexcept; // exposition only</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>      friend class basic_format_arg&lt;Context&gt;;                     // exposition only</span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a><span class="st">-     void format(basic_format_parse_context&lt;char_type&gt;&amp;, Context&amp; ctx) const;</span></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr void format(basic_format_parse_context&lt;char_type&gt;&amp;, Context&amp; ctx) const;</span></span>
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb18-14"><a href="#cb18-14" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>And <code class="sourceCode cpp">basic_format_args</code> in
<span>22.14.8.3 <a href="https://wg21.link/format.args">[format.args]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb19"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>    template&lt;class Context&gt;</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>    class basic_format_args {</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>      size_t size_;                               // exposition only</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>      const basic_format_arg&lt;Context&gt;* data_;     // exposition only</span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>      template&lt;class... Args&gt;</span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a><span class="st">-       basic_format_args(const <em>format-arg-store</em>&lt;Context, Args...&gt;&amp; store) noexcept;</span></span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr basic_format_args(const <em>format-arg-store</em>&lt;Context, Args...&gt;&amp; store) noexcept;</span></span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a><span class="st">-     basic_format_arg&lt;Context&gt; get(size_t i) const noexcept;</span></span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a><span class="va">+     constexpr basic_format_arg&lt;Context&gt; get(size_t i) const noexcept;</span></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a>    template&lt;class Context, class... Args&gt;</span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a>      basic_format_args(<em>format-arg-store</em>&lt;Context, Args...&gt;) -&gt; basic_format_args&lt;Context&gt;;</span>
<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>And the tuple formatter in <span>22.14.9 <a href="https://wg21.link/format.tuple">[format.tuple]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb20"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>    template&lt;class charT, formattable&lt;charT&gt;... Ts&gt;</span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>    struct formatter&lt;<em>pair-or-tuple</em>&lt;Ts...&gt;, charT&gt; {</span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>      tuple&lt;formatter&lt;remove_cvref_t&lt;Ts&gt;, charT&gt;...&gt; <em>underlying_</em>;               // exposition only</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>      basic_string_view&lt;charT&gt; <em>separator_</em> = <em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;, &quot;);      // exposition only</span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>      basic_string_view&lt;charT&gt; <em>opening-bracket_</em> = <em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;(&quot;); // exposition only</span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a>      basic_string_view&lt;charT&gt; <em>closing-bracket_</em> = <em>STATICALLY-WIDEN</em>&lt;charT&gt;(&quot;)&quot;); // exposition only</span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true" tabindex="-1"></a>      constexpr void set_separator(basic_string_view&lt;charT&gt; sep) noexcept;</span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true" tabindex="-1"></a>      constexpr void set_brackets(basic_string_view&lt;charT&gt; opening,</span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true" tabindex="-1"></a>                                  basic_string_view&lt;charT&gt; closing) noexcept;</span>
<span id="cb20-14"><a href="#cb20-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-15"><a href="#cb20-15" aria-hidden="true" tabindex="-1"></a>      template&lt;class ParseContext&gt;</span>
<span id="cb20-16"><a href="#cb20-16" aria-hidden="true" tabindex="-1"></a>        constexpr typename ParseContext::iterator</span>
<span id="cb20-17"><a href="#cb20-17" aria-hidden="true" tabindex="-1"></a>          parse(ParseContext&amp; ctx);</span>
<span id="cb20-18"><a href="#cb20-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-19"><a href="#cb20-19" aria-hidden="true" tabindex="-1"></a>      template&lt;class FormatContext&gt;</span>
<span id="cb20-20"><a href="#cb20-20" aria-hidden="true" tabindex="-1"></a><span class="st">-       typename FormatContext::iterator</span></span>
<span id="cb20-21"><a href="#cb20-21" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr typename FormatContext::iterator</span></span>
<span id="cb20-22"><a href="#cb20-22" aria-hidden="true" tabindex="-1"></a>          format(see below&amp; elems, FormatContext&amp; ctx) const;</span>
<span id="cb20-23"><a href="#cb20-23" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb20-24"><a href="#cb20-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb20-25"><a href="#cb20-25" aria-hidden="true" tabindex="-1"></a>    template&lt;class... Ts&gt;</span>
<span id="cb20-26"><a href="#cb20-26" aria-hidden="true" tabindex="-1"></a>      inline constexpr bool enable_nonlocking_formatter_optimization&lt;<em>pair-or-tuple</em>&lt;Ts...&gt;&gt; =</span>
<span id="cb20-27"><a href="#cb20-27" aria-hidden="true" tabindex="-1"></a>        (enable_nonlocking_formatter_optimization&lt;Ts&gt; &amp;&amp; ...);</span>
<span id="cb20-28"><a href="#cb20-28" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>Lastly, <code class="sourceCode cpp">format_error</code> for now will
remain untouched — pending a combination of <span class="citation" data-cites="P3068R1">[<a href="https://wg21.link/p3068r1" role="doc-biblioref">P3068R1</a>]</span> and <span class="citation" data-cites="P3295R0">[<a href="https://wg21.link/p3295r0" role="doc-biblioref">P3295R0</a>]</span>, since
<code class="sourceCode cpp">runtime_error</code> will also have to be
marked.</p>
<p>Mark the <code class="sourceCode cpp">vector<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;::</span>reference</code>
formatter
<code class="sourceCode cpp"><span class="kw">constexpr</span></code> in
<span>24.3.13.2 <a href="https://wg21.link/vector.bool.fmt">[vector.bool.fmt]</a></span>:</p>
<div class="std">
<blockquote>
<div>
<div class="sourceCode" id="cb21"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>    template&lt;class T, class charT&gt;</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>      requires <em>is-vector-bool-reference</em>&lt;T&gt;</span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a>    struct formatter&lt;T, charT&gt; {</span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>      formatter&lt;bool, charT&gt; <em>underlying_</em>;       // exposition only</span>
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a>      template&lt;class ParseContext&gt;</span>
<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>        constexpr typename ParseContext::iterator</span>
<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a>          parse(ParseContext&amp; ctx);</span>
<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a>      template&lt;class FormatContext&gt;</span>
<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a><span class="st">-       typename FormatContext::iterator</span></span>
<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr typename FormatContext::iterator</span></span>
<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a>          format(const T&amp; ref, FormatContext&amp; ctx) const;</span>
<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<p>And the container adaptors in <span>24.6.13 <a href="https://wg21.link/container.adaptors.format">[container.adaptors.format]</a></span>:</p>
<div class="std">
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized" href="#pnum_8" id="pnum_8">1</a></span>
For each of <code class="sourceCode cpp">queue</code>,
<code class="sourceCode cpp">priority_queue</code>, and
<code class="sourceCode cpp">stack</code>, the library provides the
following <span class="addu">constexpr-enabled</span>
<code class="sourceCode cpp">formatter</code> specialization where
<code class="sourceCode cpp"><em>adaptor-type</em></code> is the name of
the template:</p>
<div>
<div class="sourceCode" id="cb22"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>  namespace std {</span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>    template&lt;class charT, class T, formattable&lt;charT&gt; Container, class... U&gt;</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    struct formatter&lt;<em>adaptor-type</em>&lt;T, Container, U...&gt;, charT&gt; {</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a>    private:</span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a>      using <em>maybe-const-container</em> =                                             // exposition only</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a>        <em>fmt-maybe-const</em>&lt;Container, charT&gt;;</span>
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a>      using <em>maybe-const-adaptor</em> =                                               // exposition only</span>
<span id="cb22-8"><a href="#cb22-8" aria-hidden="true" tabindex="-1"></a>        <em>maybe-const</em>&lt;is_const_v&lt;<em>maybe-const-container</em>&gt;,                          // see [ranges.syn]</span>
<span id="cb22-9"><a href="#cb22-9" aria-hidden="true" tabindex="-1"></a>                    <em>adaptor-type</em>&lt;T, Container, U...&gt;&gt;;</span>
<span id="cb22-10"><a href="#cb22-10" aria-hidden="true" tabindex="-1"></a>      formatter&lt;ranges::ref_view&lt;<em>maybe-const-container</em>&gt;, charT&gt; <em>underlying_</em>;    // exposition only</span>
<span id="cb22-11"><a href="#cb22-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-12"><a href="#cb22-12" aria-hidden="true" tabindex="-1"></a>    public:</span>
<span id="cb22-13"><a href="#cb22-13" aria-hidden="true" tabindex="-1"></a>      template&lt;class ParseContext&gt;</span>
<span id="cb22-14"><a href="#cb22-14" aria-hidden="true" tabindex="-1"></a>        constexpr typename ParseContext::iterator</span>
<span id="cb22-15"><a href="#cb22-15" aria-hidden="true" tabindex="-1"></a>          parse(ParseContext&amp; ctx);</span>
<span id="cb22-16"><a href="#cb22-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb22-17"><a href="#cb22-17" aria-hidden="true" tabindex="-1"></a>      template&lt;class FormatContext&gt;</span>
<span id="cb22-18"><a href="#cb22-18" aria-hidden="true" tabindex="-1"></a><span class="st">-       typename FormatContext::iterator</span></span>
<span id="cb22-19"><a href="#cb22-19" aria-hidden="true" tabindex="-1"></a><span class="va">+       constexpr typename FormatContext::iterator</span></span>
<span id="cb22-20"><a href="#cb22-20" aria-hidden="true" tabindex="-1"></a>          format(maybe-const-adaptor&amp; r, FormatContext&amp; ctx) const;</span>
<span id="cb22-21"><a href="#cb22-21" aria-hidden="true" tabindex="-1"></a>    };</span>
<span id="cb22-22"><a href="#cb22-22" aria-hidden="true" tabindex="-1"></a>  }</span></code></pre></div>
</div>
</blockquote>
</div>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">3</span>
References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-P2291R3" class="csl-entry" role="doc-biblioentry">
[P2291R3] Daniil Goncharov, Karaev Alexander. 2021-09-23. Add Constexpr
Modifiers to Functions to_chars and from_chars for Integral Types in
Header. <a href="https://wg21.link/p2291r3"><div class="csl-block">https://wg21.link/p2291r3</div></a>
</div>
<div id="ref-P2738R1" class="csl-entry" role="doc-biblioentry">
[P2738R1] Corentin Jabot, David Ledger. 2023-02-13. constexpr cast from
void*: towards constexpr type-erasure. <a href="https://wg21.link/p2738r1"><div class="csl-block">https://wg21.link/p2738r1</div></a>
</div>
<div id="ref-P2741R3" class="csl-entry" role="doc-biblioentry">
[P2741R3] Corentin Jabot. 2023-06-16. user-generated static_assert
messages. <a href="https://wg21.link/p2741r3"><div class="csl-block">https://wg21.link/p2741r3</div></a>
</div>
<div id="ref-P2747R2" class="csl-entry" role="doc-biblioentry">
[P2747R2] Barry Revzin. 2024-03-19. constexpr placement new. <a href="https://wg21.link/p2747r2"><div class="csl-block">https://wg21.link/p2747r2</div></a>
</div>
<div id="ref-P3068R1" class="csl-entry" role="doc-biblioentry">
[P3068R1] Hana Dusíková. 2024-03-30. Allowing exception throwing in
constant-evaluation. <a href="https://wg21.link/p3068r1"><div class="csl-block">https://wg21.link/p3068r1</div></a>
</div>
<div id="ref-P3295R0" class="csl-entry" role="doc-biblioentry">
[P3295R0] Ben Craig. 2024-05-21. Freestanding constexpr containers and
constexpr exception types. <a href="https://wg21.link/p3295r0"><div class="csl-block">https://wg21.link/p3295r0</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
