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

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

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

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

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center"><code class="sourceCode default">std::constexpr_v</code></h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2781R2</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2023-05-17</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      LEWG-I<br>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Matthias Kretz<br>&lt;<a href="mailto:m.kretz@gsi.de" class="email">m.kretz@gsi.de</a>&gt;<br>
      Zach Laine<br>&lt;<a href="mailto:whatwasthataddress@gmail.com" class="email">whatwasthataddress@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="#changelog" id="toc-changelog"><span class="toc-section-number">1</span> Changelog<span></span></a>
<ul>
<li><a href="#changes-since-r0" id="toc-changes-since-r0"><span class="toc-section-number">1.1</span> Changes since
R0<span></span></a></li>
<li><a href="#changes-since-r1" id="toc-changes-since-r1"><span class="toc-section-number">1.2</span> Changes since
R1<span></span></a></li>
</ul></li>
<li><a href="#relationship-to-previous-work" id="toc-relationship-to-previous-work"><span class="toc-section-number">2</span> Relationship to previous
work<span></span></a></li>
<li><a href="#the-ergonomics-of-stdintegral_constantint-are-bad" id="toc-the-ergonomics-of-stdintegral_constantint-are-bad"><span class="toc-section-number">3</span> The ergonomics of <code class="sourceCode default">std::integral_constant&lt;int&gt;</code> are
bad<span></span></a>
<ul>
<li><a href="#replacing-the-uses-of-stdintegral_constant-is-not-enough" id="toc-replacing-the-uses-of-stdintegral_constant-is-not-enough"><span class="toc-section-number">3.1</span> Replacing the uses of
<code class="sourceCode default">std::integral_constant</code> is not
enough<span></span></a></li>
<li><a href="#the-difference-in-template-parameters-to-stdconstexpr_v-and-stdc_" id="toc-the-difference-in-template-parameters-to-stdconstexpr_v-and-stdc_"><span class="toc-section-number">3.2</span> The difference in template
parameters to <code class="sourceCode default">std::constexpr_v</code>
and
<code class="sourceCode default">std::c_</code><span></span></a></li>
</ul></li>
<li><a href="#making-constexpr_v-more-useful" id="toc-making-constexpr_v-more-useful"><span class="toc-section-number">4</span> Making
<code class="sourceCode default">constexpr_v</code> more
useful<span></span></a></li>
<li><a href="#what-about-strings" id="toc-what-about-strings"><span class="toc-section-number">5</span> What about
strings?<span></span></a></li>
<li><a href="#an-example-using-operator" id="toc-an-example-using-operator"><span class="toc-section-number">6</span> An example using
<code class="sourceCode default">operator()</code><span></span></a></li>
<li><a href="#what-about-the-mutating-operators" id="toc-what-about-the-mutating-operators"><span class="toc-section-number">7</span> What about the mutating
operators?<span></span></a>
<ul>
<li><a href="#possible-lewg-poll" id="toc-possible-lewg-poll"><span class="toc-section-number">7.0.1</span> Possible LEWG
poll<span></span></a></li>
</ul></li>
<li><a href="#what-about-operator-" id="toc-what-about-operator-"><span class="toc-section-number">8</span> What about
<code class="sourceCode default">operator-&gt;</code>?<span></span></a></li>
<li><a href="#convertibility-to-and-from-stdintegral_constant" id="toc-convertibility-to-and-from-stdintegral_constant"><span class="toc-section-number">9</span> Convertibility to and from
<code class="sourceCode default">std::integral_constant</code><span></span></a></li>
<li><a href="#design" id="toc-design"><span class="toc-section-number">10</span> Design<span></span></a>
<ul>
<li><a href="#add-constexpr_v" id="toc-add-constexpr_v"><span class="toc-section-number">10.1</span> Add
<code class="sourceCode default">constexpr_v</code><span></span></a></li>
<li><a href="#add-a-feature-macro" id="toc-add-a-feature-macro"><span class="toc-section-number">10.2</span> Add a feature
macro<span></span></a></li>
</ul></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">11</span> Implementation
experience<span></span></a></li>
<li><a href="#possible-polls-for-lewg" id="toc-possible-polls-for-lewg"><span class="toc-section-number">12</span> Possible polls for
LEWG<span></span></a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">13</span> Wording<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="changelog"><span class="header-section-number">1</span> Changelog<a href="#changelog" class="self-link"></a></h1>
<h2 data-number="1.1" id="changes-since-r0"><span class="header-section-number">1.1</span> Changes since R0<a href="#changes-since-r0" class="self-link"></a></h2>
<ul>
<li>Remove discussion of literals for
<code class="sourceCode default">std::integral_constant</code> and
<code class="sourceCode default">std::constexpr_v</code>, based on LEWG
feedback.</li>
<li>Change the title to reflect the loss of the literals.</li>
<li>Add an explicit example involving
<code class="sourceCode default">std::constexpr_v::operator()</code>, as
requested by LEWG.</li>
<li>Add concept
<code class="sourceCode default">std::constexpr_value</code>, as
suggested by LEWG.</li>
<li>Wording.</li>
</ul>
<h2 data-number="1.2" id="changes-since-r1"><span class="header-section-number">1.2</span> Changes since R1<a href="#changes-since-r1" class="self-link"></a></h2>
<ul>
<li>Remove the <code class="sourceCode default">constexpr_value</code>
concept.</li>
<li>Use an <code class="sourceCode default">auto</code> NTTP parameter
for <code class="sourceCode default">constexpr_v</code>, and default its
type template parameter.</li>
<li>Add the option for adding the mutating overloadable operators.</li>
<li>Add a note about
<code class="sourceCode default">operator-&gt;</code>.</li>
<li>Add remarks about interconvertibility with
<code class="sourceCode default">std::integral_constant</code>.</li>
<li>Reduce the number of naming options.</li>
<li>Simplify the implementation.</li>
</ul>
<h1 data-number="2" id="relationship-to-previous-work"><span class="header-section-number">2</span> Relationship to previous work<a href="#relationship-to-previous-work" class="self-link"></a></h1>
<p>This paper is co-authored by the authors of P2725R1
(“<code class="sourceCode default">std::integral_constant</code>
Literals”) and P2772R0
(“<code class="sourceCode default">std::integral_constant</code>
literals do not suffice —
<code class="sourceCode default">constexpr_t</code>?”). This paper
supersedes both of those previous papers.</p>
<h1 data-number="3" id="the-ergonomics-of-stdintegral_constantint-are-bad"><span class="header-section-number">3</span> The ergonomics of <code class="sourceCode default">std::integral_constant&lt;int&gt;</code> are
bad<a href="#the-ergonomics-of-stdintegral_constantint-are-bad" class="self-link"></a></h1>
<p><code class="sourceCode default">std::integral_constant&lt;int&gt;</code> is
used in lots of places to communicate a constant integral value to a
given interface. The length of its spelling makes it very verbose.
Fortunately, we can do a lot better.</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Before</strong>
</div></th>
<th><div style="text-align:center">
<strong>After</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<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="co">// From P2630R1</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> <span class="kw">const</span> sir <span class="op">=</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>strided_index_range<span class="op">{</span>std<span class="op">::</span>integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">0</span><span class="op">&gt;{}</span>,</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>                           std<span class="op">::</span>integral_constant<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">10</span><span class="op">&gt;{}</span>,</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>                           <span class="dv">3</span><span class="op">}</span>;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> y <span class="op">=</span> submdspan<span class="op">(</span>x, sir<span class="op">)</span>;</span></code></pre></div>

</div></td>
<td><div>

<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">auto</span> y <span class="op">=</span> submdspan<span class="op">(</span>x, std<span class="op">::</span>strided_index_range<span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>c_<span class="op">&lt;</span><span class="dv">0</span><span class="op">&gt;</span>, std<span class="op">::</span>c_<span class="op">&lt;</span><span class="dv">10</span><span class="op">&gt;</span>, <span class="dv">3</span><span class="op">})</span>;</span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>The “after” case above would require that
<code class="sourceCode default">std::strided_index_range</code> be
changed; that is not being proposed here. The point of the example is to
show the relative convenience of
<code class="sourceCode default">std::integral_constant</code> versus
the proposed
<code class="sourceCode default">std::constexpr_v</code>.</p>
<h2 data-number="3.1" id="replacing-the-uses-of-stdintegral_constant-is-not-enough"><span class="header-section-number">3.1</span> Replacing the uses of
<code class="sourceCode default">std::integral_constant</code> is not
enough<a href="#replacing-the-uses-of-stdintegral_constant-is-not-enough" class="self-link"></a></h2>
<p>Parameters passed to a
<code class="sourceCode default">constexpr</code> function lose their
<code class="sourceCode default">constexpr</code>-ness when used inside
the function. Replacing
<code class="sourceCode default">std::integral_constant</code> with
<code class="sourceCode default">std::constexpr_v</code> has the
potential to improve a lot more uses of compile-time constants than just
integrals; what about all the other
<code class="sourceCode default">constexpr</code>-friendly C++
types?</p>
<p>Consider:</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> T<span class="op">&gt;</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> my_complex</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>    T re, im;</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>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> <span class="dt">short</span> foo <span class="op">=</span> <span class="dv">2</span>;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> X</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>    <span class="dt">void</span> f<span class="op">(</span><span class="kw">auto</span> c<span class="op">)</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>        <span class="co">// c is to be used as a constexpr value here</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>We would like to be able to call
<code class="sourceCode default">X::f()</code> with a value, and have
that value keep its
<code class="sourceCode default">constexpr</code>-ness. Let’s introduce
a template “<code class="sourceCode default">constexpr_v</code>” that
holds a <code class="sourceCode default">constexpr</code> value that it
is given as an non-type template parameter.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> X, <span class="kw">class</span> T<span class="co">/* = remove_cvref_t&lt;decltype(X)&gt;*/</span><span class="op">&gt;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> constexpr_v</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> value_type <span class="op">=</span> T;</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> type <span class="op">=</span> constexpr_v;</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">operator</span> value_type<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> X; <span class="op">}</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> value_type value <span class="op">=</span> X;</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// The rest of the members are discussed below ....</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Now we can write this.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> g<span class="op">(</span>X<span class="op">&lt;</span>T<span class="op">&gt;</span> x<span class="op">)</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>constexpr_v<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;{})</span>;</span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>constexpr_v<span class="op">&lt;</span><span class="dv">2</span><span class="bu">u</span><span class="er">z</span><span class="op">&gt;{})</span>;</span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>constexpr_v<span class="op">&lt;</span><span class="fl">3.0</span><span class="op">&gt;{})</span>;</span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>constexpr_v<span class="op">&lt;</span><span class="fl">4.</span><span class="bu">f</span><span class="op">&gt;{})</span>;</span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>constexpr_v<span class="op">&lt;</span>foo<span class="op">&gt;{})</span>;</span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>constexpr_v<span class="op">&lt;</span>my_complex<span class="op">(</span><span class="fl">1.</span><span class="bu">f</span>, <span class="fl">1.</span><span class="bu">f</span><span class="op">)&gt;{})</span>;</span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Let’s now add a <code class="sourceCode default">constexpr</code>
variable template with a shorter name, say
<code class="sourceCode default">c_</code>.</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">namespace</span> std <span class="op">{</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;</span><span class="kw">auto</span> X<span class="op">&gt;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">inline</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>X<span class="op">&gt;</span> c_<span class="op">{}</span>;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>And now we can write this.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> g<span class="op">(</span>X<span class="op">&lt;</span>T<span class="op">&gt;</span> x<span class="op">)</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;)</span>;</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span><span class="dv">2</span><span class="bu">u</span><span class="er">z</span><span class="op">&gt;)</span>;</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span><span class="fl">3.0</span><span class="op">&gt;)</span>;</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span><span class="fl">4.</span><span class="bu">f</span><span class="op">&gt;)</span>;</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span>foo<span class="op">&gt;)</span>;</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>    x<span class="op">.</span>f<span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span>my_complex<span class="op">(</span><span class="fl">1.</span><span class="bu">f</span>, <span class="fl">1.</span><span class="bu">f</span><span class="op">)&gt;)</span>;</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="3.2" id="the-difference-in-template-parameters-to-stdconstexpr_v-and-stdc_"><span class="header-section-number">3.2</span> The difference in template
parameters to <code class="sourceCode default">std::constexpr_v</code>
and <code class="sourceCode default">std::c_</code><a href="#the-difference-in-template-parameters-to-stdconstexpr_v-and-stdc_" class="self-link"></a></h2>
<p><code class="sourceCode default">std::c_</code> takes an
<code class="sourceCode default">auto</code> NTTP.
<code class="sourceCode default">std::constexpr_v</code> takes an
<code class="sourceCode default">auto</code> NTTP
<code class="sourceCode default">X</code>, and a type
<code class="sourceCode default">T</code> which is defaulted to
<code class="sourceCode default">decltype(X)</code>. Why is this? ADL!
Even thought the type of <code class="sourceCode default">X</code> is
deduced with our without <code class="sourceCode default">T</code>,
without <code class="sourceCode default">T</code> some natural uses of
<code class="sourceCode default">constexpr_v</code> cease to work. For
instance:</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">auto</span> f <span class="op">=</span> std<span class="op">::</span>c_<span class="op">&lt;</span>strlit<span class="op">(</span><span class="st">&quot;foo&quot;</span><span class="op">)&gt;</span>; <span class="co">// Using the strlit from later in this paper.</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> f <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span></code></pre></div>
<p>The stream insertion breaks without the
<code class="sourceCode default">T</code> parameter. The
<code class="sourceCode default">T</code> parameter is
<code class="sourceCode default">strlit&lt;/*...*/&gt;</code>, which
pulls <code class="sourceCode default">strlit</code>’s
<code class="sourceCode default">operator&lt;&lt;</code> into
consideration during ADL.</p>
<h1 data-number="4" id="making-constexpr_v-more-useful"><span class="header-section-number">4</span> Making
<code class="sourceCode default">constexpr_v</code> more useful<a href="#making-constexpr_v-more-useful" class="self-link"></a></h1>
<p><code class="sourceCode default">constexpr_v</code> is essentially a
wrapper. It takes a value <code class="sourceCode default">X</code> of
some structural type <code class="sourceCode default">T</code>, and
represents <code class="sourceCode default">X</code> in such a way that
we can continue to use <code class="sourceCode default">X</code> as a
compile-time constant, regardless of context. As such,
<code class="sourceCode default">constexpr_v</code> should be implicitly
convertible to <code class="sourceCode default">T</code>; this is
already reflected in the design presented above. For the same reason,
<code class="sourceCode default">constexpr_v</code> should provide all
the operations that the underlying type has. Though we cannot predict
what named members the underlying type
<code class="sourceCode default">T</code> has, we <em>can</em> guess at
all the operator overloads it might have.</p>
<p>So, by adding conditionally-defined overloads for all the
overloadable operators, we can make
<code class="sourceCode default">constexpr_v</code> as natural to use as
many of the types it might wrap.</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">namespace</span> std <span class="op">{</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> X, <span class="kw">class</span> T<span class="co">/* = remove_cvref_t&lt;decltype(X)&gt;*/</span><span class="op">&gt;</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> constexpr_v <span class="op">{</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> value_type <span class="op">=</span> T;</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> type <span class="op">=</span> constexpr_v;</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">operator</span> value_type<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> X; <span class="op">}</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> value_type value <span class="op">=</span> X;</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>    <span class="co">// unary -</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> Y <span class="op">=</span> X<span class="op">&gt;</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-()</span> <span class="kw">const</span> <span class="op">-&gt;</span> constexpr_v<span class="op">&lt;-</span>Y<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a>    <span class="co">// binary + and -</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">+</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">+(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb9-18"><a href="#cb9-18" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">-</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">-(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb9-19"><a href="#cb9-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-20"><a href="#cb9-20" aria-hidden="true" tabindex="-1"></a>    <span class="co">// etc... (full listing later)</span></span>
<span id="cb9-21"><a href="#cb9-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb9-22"><a href="#cb9-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>These operators are defined in such a way that they behave just like
the operations on underlying the
<code class="sourceCode default">T</code> and
<code class="sourceCode default">V</code> values would, including
promotions and coercions. For example:</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">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>              <span class="kw">decltype</span><span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span><span class="dv">42</span><span class="op">&gt;</span> <span class="op">-</span> std<span class="op">::</span>c_<span class="op">&lt;</span><span class="dv">13</span><span class="bu">u</span><span class="op">&gt;)</span>,</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>              std<span class="op">::</span>constexpr_v<span class="op">&lt;</span><span class="dv">29</span><span class="bu">u</span><span class="op">&gt;&gt;)</span>;</span></code></pre></div>
<p>Each operation is only defined if the underlying operation on
<code class="sourceCode default">X</code> and
<code class="sourceCode default">Y</code> is defined. Each operation
additionally requires that the result of the underlying operation have a
structural type.</p>
<p>The mutating operations are left out, because none of them makes
sense – the type of the mutated value would have to change, since the
value is itself part of the type.</p>
<p>All the remaining operations are included, even the index and call
operators. The rationale for this is that a user may want to make some
sort of compile-time domain-specific embedded language using operator
overloading, and having all but a couple of the operators specified
would frustrate that effort.</p>
<p>The only downside to adding
<code class="sourceCode default">std::constexpr_v::operator()()</code>
is that it would represent a break from the design of
<code class="sourceCode default">std::integral_constant</code>, making
it an imperfect drop-in replacement for that template.</p>
<p>The operators are designed to interoperate with other types and
templates that have a constexpr static
<code class="sourceCode default">value</code> member. This works with
<code class="sourceCode default">std::constexpr_v</code>s of course, but
also <code class="sourceCode default">std::integral_constant</code>s,
and user-provided types as well. For example:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> my_type <span class="op">{</span> <span class="kw">constexpr</span> <span class="kw">static</span> <span class="dt">int</span> value <span class="op">=</span> <span class="dv">42</span>; <span class="op">}</span>;</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">()</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> zero <span class="op">=</span> my_type<span class="op">{}</span> <span class="op">-</span> std<span class="op">::</span>c_<span class="op">&lt;</span><span class="dv">42</span><span class="op">&gt;</span>;  <span class="co">// Ok.</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// ...</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Note that the addition of these operators is in line with the
poll:</p>
<p>“Add a new robust integral constant type with all the numerical
operators, as proposed in P2772R0, and use that for these literals
instead of
<code class="sourceCode default">std::integral_constant</code>”?</p>
<table style="width:31%;">
<colgroup>
<col style="width: 6%" />
<col style="width: 5%" />
<col style="width: 5%" />
<col style="width: 5%" />
<col style="width: 6%" />
</colgroup>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>4</td>
<td>7</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>… taken in the 2023-01-17 Library Evolution telecon.</p>
<p>Note that the one SA said he would not be opposed if the word
“integral” was stricken from the poll, and the design of
<code class="sourceCode default">std::constexpr_v</code> is not limited
to integral types.</p>
<h1 data-number="5" id="what-about-strings"><span class="header-section-number">5</span> What about strings?<a href="#what-about-strings" class="self-link"></a></h1>
<p>As pointed out on the reflector,
<code class="sourceCode default">std::c_&lt;&quot;foo&quot;&gt;</code>
does not work, because of language rules. However, it’s pretty easy for
users to add an NTTP-friendly string wrapper type, and then use that
with <code class="sourceCode default">std::c_&lt;&gt;</code>.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> strlit</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> strlit<span class="op">(</span><span class="dt">char</span> <span class="kw">const</span> <span class="op">(&amp;</span>str<span class="op">)[</span>N<span class="op">])</span> <span class="op">{</span> std<span class="op">::</span>copy_n<span class="op">(</span>str, N, value<span class="op">)</span>; <span class="op">}</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> M<span class="op">&gt;</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>strlit<span class="op">&lt;</span>M<span class="op">&gt;</span> rhs<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> std<span class="op">::</span>ranges<span class="op">::</span>equal<span class="op">(</span>bytes_, rhs<span class="op">.</span>bytes_<span class="op">)</span>;</span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> std<span class="op">::</span>ostream <span class="op">&amp;</span> <span class="kw">operator</span><span class="op">&lt;&lt;(</span>std<span class="op">::</span>ostream <span class="op">&amp;</span> os, strlit l<span class="op">)</span></span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>        <span class="ot">assert</span><span class="op">(!</span>l<span class="op">.</span>value<span class="op">[</span>N <span class="op">-</span> <span class="dv">1</span><span class="op">]</span> <span class="op">&amp;&amp;</span> <span class="st">&quot;value must be null-terminated&quot;</span><span class="op">)</span>;</span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> os<span class="op">.</span>write<span class="op">(</span>l<span class="op">.</span>value, N <span class="op">-</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span> value<span class="op">[</span>N<span class="op">]</span>;</span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</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><span class="dt">int</span> main<span class="op">()</span></span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> f <span class="op">=</span> std<span class="op">::</span>c_<span class="op">&lt;</span>strlit<span class="op">(</span><span class="st">&quot;foo&quot;</span><span class="op">)&gt;</span>;</span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cout <span class="op">&lt;&lt;</span> f; <span class="co">// Prints &quot;foo&quot;.</span></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="6" id="an-example-using-operator"><span class="header-section-number">6</span> An example using
<code class="sourceCode default">operator()</code><a href="#an-example-using-operator" class="self-link"></a></h1>
<p>The addition of non-arithmetic operators may seem academic at first.
However, consider this
<code class="sourceCode default">constexpr</code>-friendly parser
combinator mini-library.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> parse <span class="op">{</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> L, <span class="kw">typename</span> R<span class="op">&gt;</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> or_parser;</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-6"><a href="#cb13-6" 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>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> str_parser</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>        <span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> M<span class="op">&gt;</span></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">()(</span>strlit<span class="op">&lt;</span>M<span class="op">&gt;</span> lit<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> lit <span class="op">==</span> str_;</span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>        <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> P<span class="op">&gt;</span></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">|(</span>P parser<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> or_parser<span class="op">&lt;</span>str_parser, P<span class="op">&gt;{*</span><span class="kw">this</span>, parser<span class="op">}</span>;</span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a>        strlit<span class="op">&lt;</span>N<span class="op">&gt;</span> str_;</span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> L, <span class="kw">typename</span> R<span class="op">&gt;</span></span>
<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> or_parser</span>
<span id="cb13-24"><a href="#cb13-24" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb13-25"><a href="#cb13-25" aria-hidden="true" tabindex="-1"></a>        <span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> M<span class="op">&gt;</span></span>
<span id="cb13-26"><a href="#cb13-26" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">()(</span>strlit<span class="op">&lt;</span>M<span class="op">&gt;</span> lit<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb13-27"><a href="#cb13-27" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb13-28"><a href="#cb13-28" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> l_<span class="op">(</span>lit<span class="op">)</span> <span class="op">||</span> r_<span class="op">(</span>lit<span class="op">)</span>;</span>
<span id="cb13-29"><a href="#cb13-29" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb13-30"><a href="#cb13-30" aria-hidden="true" tabindex="-1"></a>        <span class="kw">template</span><span class="op">&lt;</span><span class="kw">typename</span> P<span class="op">&gt;</span></span>
<span id="cb13-31"><a href="#cb13-31" aria-hidden="true" tabindex="-1"></a>        <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">|(</span>P parser<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb13-32"><a href="#cb13-32" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb13-33"><a href="#cb13-33" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> or_parser<span class="op">&lt;</span>or_parser, P<span class="op">&gt;{*</span><span class="kw">this</span>, parser<span class="op">}</span>;</span>
<span id="cb13-34"><a href="#cb13-34" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb13-35"><a href="#cb13-35" aria-hidden="true" tabindex="-1"></a>        L l_;</span>
<span id="cb13-36"><a href="#cb13-36" aria-hidden="true" tabindex="-1"></a>        R r_;</span>
<span id="cb13-37"><a href="#cb13-37" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb13-38"><a href="#cb13-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-39"><a href="#cb13-39" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb13-40"><a href="#cb13-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-41"><a href="#cb13-41" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> foo<span class="op">()</span></span>
<span id="cb13-42"><a href="#cb13-42" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb13-43"><a href="#cb13-43" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> parse<span class="op">::</span>str_parser p1<span class="op">{</span>strlit<span class="op">(</span><span class="st">&quot;neg&quot;</span><span class="op">)}</span>;</span>
<span id="cb13-44"><a href="#cb13-44" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> parse<span class="op">::</span>str_parser p2<span class="op">{</span>strlit<span class="op">(</span><span class="st">&quot;incr&quot;</span><span class="op">)}</span>;</span>
<span id="cb13-45"><a href="#cb13-45" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> parse<span class="op">::</span>str_parser p3<span class="op">{</span>strlit<span class="op">(</span><span class="st">&quot;decr&quot;</span><span class="op">)}</span>;</span>
<span id="cb13-46"><a href="#cb13-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-47"><a href="#cb13-47" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> p <span class="op">=</span> p1 <span class="op">|</span> p2 <span class="op">|</span> p3;</span>
<span id="cb13-48"><a href="#cb13-48" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-49"><a href="#cb13-49" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> matches_empty <span class="op">=</span> p<span class="op">(</span>strlit<span class="op">(</span><span class="st">&quot;&quot;</span><span class="op">))</span>;</span>
<span id="cb13-50"><a href="#cb13-50" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(!</span>matches_empty<span class="op">)</span>;</span>
<span id="cb13-51"><a href="#cb13-51" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> matches_pos <span class="op">=</span> p<span class="op">(</span>strlit<span class="op">(</span><span class="st">&quot;pos&quot;</span><span class="op">))</span>;</span>
<span id="cb13-52"><a href="#cb13-52" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(!</span>matches_pos<span class="op">)</span>;</span>
<span id="cb13-53"><a href="#cb13-53" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> matches_decr <span class="op">=</span> p<span class="op">(</span>strlit<span class="op">(</span><span class="st">&quot;decr&quot;</span><span class="op">))</span>;</span>
<span id="cb13-54"><a href="#cb13-54" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>matches_decr<span class="op">)</span>;</span>
<span id="cb13-55"><a href="#cb13-55" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>(This relies on the <code class="sourceCode default">strlit</code>
struct shown just previously.)</p>
<p>Say we wanted to use the templates in namespace
<code class="sourceCode default">parser</code> along side other values,
like <code class="sourceCode default">int</code>s and
<code class="sourceCode default">float</code>s. We would want that not
to break our <code class="sourceCode default">std::constexpr_v</code>
expressions. Having to work around the absence of
<code class="sourceCode default">std::constexpr_v::operator()</code>
would require us to write a lot more code. Here is the equivalent of the
function <code class="sourceCode default">foo()</code> above, but with
all the variables wrapped using
<code class="sourceCode default">std::c_</code>.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> bar<span class="op">()</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> parse<span class="op">::</span>str_parser p1<span class="op">{</span>strlit<span class="op">(</span><span class="st">&quot;neg&quot;</span><span class="op">)}</span>;</span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> parse<span class="op">::</span>str_parser p2<span class="op">{</span>strlit<span class="op">(</span><span class="st">&quot;incr&quot;</span><span class="op">)}</span>;</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> parse<span class="op">::</span>str_parser p3<span class="op">{</span>strlit<span class="op">(</span><span class="st">&quot;decr&quot;</span><span class="op">)}</span>;</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> p_ <span class="op">=</span> std<span class="op">::</span>c_<span class="op">&lt;</span>p1<span class="op">&gt;</span> <span class="op">|</span> std<span class="op">::</span>c_<span class="op">&lt;</span>p2<span class="op">&gt;</span> <span class="op">|</span> std<span class="op">::</span>c_<span class="op">&lt;</span>p3<span class="op">&gt;</span>;</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> matches_empty_ <span class="op">=</span> p_<span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span>strlit<span class="op">(</span><span class="st">&quot;&quot;</span><span class="op">)&gt;)</span>;</span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(!</span>matches_empty_<span class="op">)</span>;</span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> matches_pos_ <span class="op">=</span> p_<span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span>strlit<span class="op">(</span><span class="st">&quot;pos&quot;</span><span class="op">)&gt;)</span>;</span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(!</span>matches_pos_<span class="op">)</span>;</span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> matches_decr_ <span class="op">=</span> p_<span class="op">(</span>std<span class="op">::</span>c_<span class="op">&lt;</span>strlit<span class="op">(</span><span class="st">&quot;decr&quot;</span><span class="op">)&gt;)</span>;</span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>matches_decr_<span class="op">)</span>;</span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>As you can see, everything works as it did before. The presence of
<code class="sourceCode default">operator()</code> does not enable any
new functionality, it just keeps code that happens to use it from
breaking.</p>
<h1 data-number="7" id="what-about-the-mutating-operators"><span class="header-section-number">7</span> What about the mutating
operators?<a href="#what-about-the-mutating-operators" class="self-link"></a></h1>
<p>The operators left out of the code below are the ones that involve
mutation, like <code class="sourceCode default">operator++</code>,
<code class="sourceCode default">operator/=</code>, etc. These seem at
first that these are nonsensical, since all the operations on a
<code class="sourceCode default">constexpr_v</code> must be
nonmutating.</p>
<p>However, some DSLs may wish to use these operations with atypical
semantics.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> weirdo</span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">int</span> <span class="kw">operator</span><span class="op">++()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> <span class="dv">1</span>; <span class="op">}</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> <span class="op">++</span>std<span class="op">::</span>c_<span class="op">&lt;</span>weirdo<span class="op">{}&gt;</span>;</span></code></pre></div>
<p><code class="sourceCode default">result</code> is obviously
<code class="sourceCode default">std::c_&lt;1&gt;</code> here, and no
mutation occurred. You can imagine a more elaborate use case, say a
library that is used to create expression templates. For example:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> expr <span class="op">=</span> std<span class="op">::</span>c_<span class="op">&lt;</span>var0<span class="op">&gt;</span> <span class="op">+=</span> std<span class="op">::</span>c_<span class="op">&lt;</span>var1<span class="op">&gt;</span>;</span></code></pre></div>
<p>In this case, <code class="sourceCode default">var0</code> and
<code class="sourceCode default">var1</code> would be some terminal
types in the expression template library, and
<code class="sourceCode default">operator+=</code> would return a
<code class="sourceCode default">constexpr</code> expression tree,
rather than mutating the left side of the
<code class="sourceCode default">+=</code>.</p>
<p>Since this is a realtively late addition – after the paper has been
through two LEWG reviews, the addition of these operators is being
presented as an option. However, we have implemented it, and know that
they work.</p>
<p>The optional parts in the design listing and wording are marked with
<code class="sourceCode default">#if LEWG_SAYS_SO</code>.</p>
<h3 data-number="7.0.1" id="possible-lewg-poll"><span class="header-section-number">7.0.1</span> Possible LEWG poll<a href="#possible-lewg-poll" class="self-link"></a></h3>
<p>We want to add all overloadable operators to
<code class="sourceCode default">constexpr_v</code>, including the ones
that are usually mutating.</p>
<h1 data-number="8" id="what-about-operator-"><span class="header-section-number">8</span> What about
<code class="sourceCode default">operator-&gt;</code>?<a href="#what-about-operator-" class="self-link"></a></h1>
<p>We’re not proposing it, because of its very specific semantics – it
must yield a pointer, or something that eventually does. That’s not a
very useful operation during constant evaluation.</p>
<h1 data-number="9" id="convertibility-to-and-from-stdintegral_constant"><span class="header-section-number">9</span> Convertibility to and from
<code class="sourceCode default">std::integral_constant</code><a href="#convertibility-to-and-from-stdintegral_constant" class="self-link"></a></h1>
<p>During the LEWG reviews, some attendees suggested that
inter-conversions between
<code class="sourceCode default">std::integral_constant</code> and
<code class="sourceCode default">std::constexpr_v</code> would be
useful. The important thing to remember is that we want deduction to
occur when calling functions that take a
<code class="sourceCode default">std::constexpr_v</code>, including the
<code class="sourceCode default">std::constexpr_v</code> operator
overloads. Conversions and deductions are at odds with one another,
because deducing parameter types disables the conversion rules.</p>
<p>If you look at the operator overloads proposed here, you will see
that they are deduction operations at their most essential. The types of
the parameters do not matter, except that each conveys a value that is a
core constant expression because it is embedded in the type system. The
fact that a <code class="sourceCode default">std::constexpr_v</code>
conveys that value instead of a
<code class="sourceCode default">std::integral_constant</code> is
immaterial, and in fact the operators are written in such a way that
they operate on either template (as long as at least one parameter is a
specialization of
<code class="sourceCode default">std::constexpr_v</code>). Users can and
should write their code using these kinds of values-as-types in a
similar way. Relying on conversions is a less-useful way to get
interoperability.</p>
<h1 data-number="10" id="design"><span class="header-section-number">10</span> Design<a href="#design" class="self-link"></a></h1>
<h2 data-number="10.1" id="add-constexpr_v"><span class="header-section-number">10.1</span> Add
<code class="sourceCode default">constexpr_v</code><a href="#add-constexpr_v" class="self-link"></a></h2>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> X, <span class="kw">class</span> T <span class="op">=</span> remove_cvref_t<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>X<span class="op">)&gt;&gt;</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> constexpr_v;</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-5"><a href="#cb17-5" 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>
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em>constexpr-param</em> <span class="op">=</span>                                <span class="co">// <em>exposition only</em></span></span>
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a>      <span class="kw">requires</span> <span class="op">{</span> <span class="kw">typename</span> constexpr_v<span class="op">&lt;</span>T<span class="op">::</span>value<span class="op">&gt;</span>; <span class="op">}</span> <span class="kw">and</span> <span class="kw">not</span> is_member_pointer_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(&amp;</span>T<span class="op">::</span>value<span class="op">)&gt;</span>;</span>
<span id="cb17-8"><a href="#cb17-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>
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em>derived-from-constexpr</em> <span class="op">=</span>                         <span class="co">// <em>exposition only</em></span></span>
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>      derived_from<span class="op">&lt;</span>T, constexpr_v<span class="op">&lt;</span>T<span class="op">::</span>value<span class="op">&gt;&gt;</span>;</span>
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> T, <span class="kw">class</span> SelfT<span class="op">&gt;</span></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a>    <span class="kw">concept</span> <em>lhs-constexpr-param</em> <span class="op">=</span>                            <span class="co">// <em>exposition only</em></span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>      <em>constexpr-param</em><span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">and</span> <span class="op">(</span>derived_from<span class="op">&lt;</span>T, SelfT<span class="op">&gt;</span> <span class="kw">or</span> <span class="kw">not</span> <em>derived-from-constexpr</em><span class="op">&lt;</span>T<span class="op">&gt;)</span>;</span>
<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> X, <span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> constexpr_v <span class="op">{</span></span>
<span id="cb17-17"><a href="#cb17-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> value_type <span class="op">=</span> T;</span>
<span id="cb17-18"><a href="#cb17-18" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> type <span class="op">=</span> constexpr_v;</span>
<span id="cb17-19"><a href="#cb17-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-20"><a href="#cb17-20" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">operator</span> value_type<span class="op">()</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> X; <span class="op">}</span></span>
<span id="cb17-21"><a href="#cb17-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> value_type value <span class="op">=</span> X;</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="pp">#if LEWG_SAYS_SO</span></span>
<span id="cb17-24"><a href="#cb17-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>constexpr-param</em> U<span class="op">&gt;</span></span>
<span id="cb17-25"><a href="#cb17-25" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>X <span class="op">=</span> U<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">=(</span>U<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-26"><a href="#cb17-26" aria-hidden="true" tabindex="-1"></a><span class="pp">#endif</span></span>
<span id="cb17-27"><a href="#cb17-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-28"><a href="#cb17-28" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> Y <span class="op">=</span> X<span class="op">&gt;</span></span>
<span id="cb17-29"><a href="#cb17-29" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">+()</span> <span class="kw">const</span> <span class="op">-&gt;</span> constexpr_v<span class="op">&lt;+</span>Y<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-30"><a href="#cb17-30" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> Y <span class="op">=</span> X<span class="op">&gt;</span></span>
<span id="cb17-31"><a href="#cb17-31" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">-()</span> <span class="kw">const</span> <span class="op">-&gt;</span> constexpr_v<span class="op">&lt;-</span>Y<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-32"><a href="#cb17-32" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> Y <span class="op">=</span> X<span class="op">&gt;</span></span>
<span id="cb17-33"><a href="#cb17-33" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">~()</span> <span class="kw">const</span> <span class="op">-&gt;</span> constexpr_v<span class="op">&lt;~</span>Y<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-34"><a href="#cb17-34" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> Y <span class="op">=</span> X<span class="op">&gt;</span></span>
<span id="cb17-35"><a href="#cb17-35" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">!()</span> <span class="kw">const</span> <span class="op">-&gt;</span> constexpr_v<span class="op">&lt;!</span>Y<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-36"><a href="#cb17-36" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> Y <span class="op">=</span> X<span class="op">&gt;</span></span>
<span id="cb17-37"><a href="#cb17-37" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">&amp;()</span> <span class="kw">const</span> <span class="op">-&gt;</span> constexpr_v<span class="op">&lt;&amp;</span>Y<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-38"><a href="#cb17-38" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> Y <span class="op">=</span> X<span class="op">&gt;</span></span>
<span id="cb17-39"><a href="#cb17-39" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">*()</span> <span class="kw">const</span> <span class="op">-&gt;</span> constexpr_v<span class="op">&lt;*</span>Y<span class="op">&gt;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-40"><a href="#cb17-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-41"><a href="#cb17-41" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb17-42"><a href="#cb17-42" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">()(</span>Args<span class="op">...</span> args<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> constexpr_v<span class="op">&lt;</span>X<span class="op">(</span>Args<span class="op">::</span>value<span class="op">...)&gt;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-43"><a href="#cb17-43" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb17-44"><a href="#cb17-44" aria-hidden="true" tabindex="-1"></a>      <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">[](</span>Args<span class="op">...</span> args<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> constexpr_v<span class="op">&lt;</span>X<span class="op">[</span>Args<span class="op">::</span>value<span class="op">...]&gt;</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-45"><a href="#cb17-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-46"><a href="#cb17-46" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-47"><a href="#cb17-47" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">+</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">+(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-48"><a href="#cb17-48" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-49"><a href="#cb17-49" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">-</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">-(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-50"><a href="#cb17-50" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-51"><a href="#cb17-51" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">*</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">*(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-52"><a href="#cb17-52" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-53"><a href="#cb17-53" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">/</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">/(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-54"><a href="#cb17-54" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-55"><a href="#cb17-55" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">%</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">%(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-56"><a href="#cb17-56" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-57"><a href="#cb17-57" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-58"><a href="#cb17-58" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&lt;&lt;</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&lt;&lt;(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-59"><a href="#cb17-59" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-60"><a href="#cb17-60" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&gt;&gt;</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&gt;&gt;(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-61"><a href="#cb17-61" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-62"><a href="#cb17-62" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">&amp;</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">&amp;(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-63"><a href="#cb17-63" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-64"><a href="#cb17-64" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">|</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">|(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-65"><a href="#cb17-65" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-66"><a href="#cb17-66" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">^</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">^(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-67"><a href="#cb17-67" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-68"><a href="#cb17-68" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-69"><a href="#cb17-69" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">&amp;&amp;</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">&amp;&amp;(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-70"><a href="#cb17-70" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-71"><a href="#cb17-71" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>U<span class="op">::</span>value <span class="op">||</span> V<span class="op">::</span>value<span class="op">&gt;</span> <span class="kw">operator</span><span class="op">||(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-72"><a href="#cb17-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-73"><a href="#cb17-73" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-74"><a href="#cb17-74" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&lt;=&gt;</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&lt;=&gt;(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-75"><a href="#cb17-75" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-76"><a href="#cb17-76" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">==</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">==(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-77"><a href="#cb17-77" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-78"><a href="#cb17-78" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">!=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">!=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-79"><a href="#cb17-79" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-80"><a href="#cb17-80" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&lt;</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&lt;(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-81"><a href="#cb17-81" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-82"><a href="#cb17-82" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&gt;</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&gt;(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-83"><a href="#cb17-83" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-84"><a href="#cb17-84" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&lt;=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&lt;=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-85"><a href="#cb17-85" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-86"><a href="#cb17-86" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&gt;=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&gt;=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-87"><a href="#cb17-87" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-88"><a href="#cb17-88" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-89"><a href="#cb17-89" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value, V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span>,<span class="op">(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-90"><a href="#cb17-90" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-91"><a href="#cb17-91" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">-&gt;*</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">-&gt;*(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-92"><a href="#cb17-92" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-93"><a href="#cb17-93" aria-hidden="true" tabindex="-1"></a><span class="pp">#if LEWG_SAYS_SO</span></span>
<span id="cb17-94"><a href="#cb17-94" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-95"><a href="#cb17-95" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">+=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">+=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-96"><a href="#cb17-96" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-97"><a href="#cb17-97" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">-=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">-=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-98"><a href="#cb17-98" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-99"><a href="#cb17-99" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">*=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">*=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-100"><a href="#cb17-100" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-101"><a href="#cb17-101" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">/=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">/=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-102"><a href="#cb17-102" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-103"><a href="#cb17-103" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">%=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">%=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-104"><a href="#cb17-104" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-105"><a href="#cb17-105" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&amp;=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&amp;=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-106"><a href="#cb17-106" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-107"><a href="#cb17-107" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">|=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">|=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-108"><a href="#cb17-108" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-109"><a href="#cb17-109" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">^=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">^=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-110"><a href="#cb17-110" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-111"><a href="#cb17-111" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&lt;&lt;=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&lt;&lt;=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-112"><a href="#cb17-112" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span> <span class="op">&lt;</span><em>lhs-constexpr-param</em><span class="op">&lt;</span>type<span class="op">&gt;</span> U, <em>constexpr-param</em> V<span class="op">&gt;</span></span>
<span id="cb17-113"><a href="#cb17-113" aria-hidden="true" tabindex="-1"></a>      <span class="kw">friend</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;(</span>U<span class="op">::</span>value <span class="op">&gt;&gt;=</span> V<span class="op">::</span>value<span class="op">)&gt;</span> <span class="kw">operator</span><span class="op">&gt;&gt;=(</span>U, V<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> <span class="op">{}</span>; <span class="op">}</span></span>
<span id="cb17-114"><a href="#cb17-114" aria-hidden="true" tabindex="-1"></a><span class="pp">#endif</span></span>
<span id="cb17-115"><a href="#cb17-115" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb17-116"><a href="#cb17-116" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-117"><a href="#cb17-117" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">auto</span> X<span class="op">&gt;</span></span>
<span id="cb17-118"><a href="#cb17-118" aria-hidden="true" tabindex="-1"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> constexpr_v<span class="op">&lt;</span>X<span class="op">&gt;</span> c_<span class="op">{}</span>;</span>
<span id="cb17-119"><a href="#cb17-119" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h2 data-number="10.2" id="add-a-feature-macro"><span class="header-section-number">10.2</span> Add a feature macro<a href="#add-a-feature-macro" class="self-link"></a></h2>
<p>Add a new feature macro,
<code class="sourceCode default">__cpp_lib_constexpr_v</code>.</p>
<h1 data-number="11" id="implementation-experience"><span class="header-section-number">11</span> Implementation experience<a href="#implementation-experience" class="self-link"></a></h1>
<p>Look up a few lines to see an implementation of
<code class="sourceCode default">std::constexpr_v</code>. At the time of
this writing, there is one caveat:
<code class="sourceCode default">operator[]()</code> looks correct to
the authors, but does not work in any compiler tested, due to the very
limited multi-variate <code class="sourceCode default">operator[]</code>
support in even the latest compilers.</p>
<p>Additionally, an
<code class="sourceCode default">integral_constant</code> with most of
the operator overloads has been a part of <a href="https://www.boost.org/doc/libs/1_80_0/libs/hana/doc/html/index.html">Boost.Hana</a>
since its initial release in May of 2016. Its operations have been used
by many, many users.</p>
<h1 data-number="12" id="possible-polls-for-lewg"><span class="header-section-number">12</span> Possible polls for LEWG<a href="#possible-polls-for-lewg" class="self-link"></a></h1>
<ul>
<li>We should call
<code class="sourceCode default">std::constexpr_v</code>:
<ol type="1">
<li><code class="sourceCode default">std::constexpr_wrapper</code>
<ul>
<li><p>Pro: The name calls out that this type has a relation to constant
expressions.</p></li>
<li><p>Pro: Consistency. The name is analoguous to
<code class="sourceCode default">std::reference_wrapper</code> (and
<code class="sourceCode default">std::ref</code>).</p></li>
<li><p>Pro:
<code class="sourceCode default">constexpr_wrapper&lt;1&gt;</code> reads
as <strong>wrapper</strong> for <strong>const</strong>ant
<strong>expr</strong>ession with value <strong>1</strong>.</p></li>
<li><p>Con: It’s a long name. However, if we expect that user typically
won’t spell out this type, then it doesn’t matter much.</p></li>
</ul></li>
<li><code class="sourceCode default">std::constexpr_t</code>
<ul>
<li><p>Pro: The name calls out that this type has a relation to constant
expressions.</p></li>
<li><p>Pro: Read the name as either “the result of a
<strong>const</strong>ant <strong>expr</strong>ession identified by a
<strong>t</strong>ype” or “a <strong>t</strong>ype identifying a value
usable in <strong>const</strong>ant
<strong>expr</strong>essions”.</p></li>
<li><p>Pro: The name calls out that it’s a type (or class template) and
not a variable template.</p></li>
<li><p>Con: <code class="sourceCode default">_t</code> in the standard
library typically means “alias template for
<code class="sourceCode default">::type</code> member of a trait”. The
use of <code class="sourceCode default">_t</code> to identify types is
more of a C thing.</p></li>
</ul></li>
<li><code class="sourceCode default">std::constexpr_value</code>
<ul>
<li><p>Pro: The name calls out that this type has a relation to constant
expressions.</p></li>
<li><p>Pro:
<code class="sourceCode default">constexpr_value&lt;1&gt;</code> can be
read as “the value 1 as a constant expression”.</p></li>
<li><p>Con: The <code class="sourceCode default">_value</code> suffix
may mislead readers to expect a variable template.</p></li>
</ul></li>
<li><code class="sourceCode default">std::constant_value</code>
<ul>
<li><p>Con: The <code class="sourceCode default">_value</code> suffix
may mislead readers to expect a variable template.</p></li>
<li><p>Con: Nothing in the type hints at the primary use case: enabling
<em>constant expressions</em>.</p></li>
<li><p>Con: The name <code class="sourceCode default">constant</code>
hints at <code class="sourceCode default">const</code>. While
<code class="sourceCode default">const</code> isn’t wrong here, it’s
also irrelevant.</p></li>
<li><p>Con:
<code class="sourceCode default">constant_value&lt;1&gt;</code> reads
pretty much like <code class="sourceCode default">const int</code> with
value <code class="sourceCode default">1</code>, which is
misleading.</p></li>
</ul></li>
</ol></li>
<li>We should call <code class="sourceCode default">std::c_</code>:
<ol type="1">
<li><code class="sourceCode default">std::cc</code>
<ul>
<li><p>short for
<strong>c</strong><code class="sourceCode default">onstexpr_wrapper</code>
<strong>c</strong>onstant (somewhat silly, sure)</p></li>
<li><p>quick to type: hit the same key twice</p></li>
<li><p>203’614 matches found on codesearch.isocpp.org</p></li>
</ul></li>
<li><code class="sourceCode default">std::c_</code>
<ul>
<li><p>hardest to type (IMHO and with US keyboard layout, i.e. type “c
shift+_ shift+&lt;”; the _ &lt; movement is slowing me down)</p></li>
<li><p>10’198 matches found on codesearch.isocpp.org</p></li>
</ul></li>
<li><code class="sourceCode default">std::cw</code>
<ul>
<li><p>short for
<strong>c</strong><code class="sourceCode default">onstexpr_</code><strong>w</strong><code class="sourceCode default">rapper</code>
or <strong>c</strong>onstexpr <strong>w</strong>rap, i.e.  read
<code class="sourceCode default">cw&lt;1&gt;</code> as “constexpr wrap
1”</p></li>
<li><p>41’311 matches found on codesearch.isocpp.org</p></li>
</ul></li>
<li><code class="sourceCode default">std::c</code>
<ul>
<li><p>3’869’416 matches found on codesearch.isocpp.org</p></li>
<li><p>scarily short</p></li>
</ul></li>
</ol></li>
</ul>
<h1 data-number="13" id="wording"><span class="header-section-number">13</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>Add the following to [meta.type.synop], after
<code class="sourceCode default">false_type</code>:</p>
<div class="add" style="color: #006e28">

<div class="sourceCode" id="cb18"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>template&lt;auto X, class T = remove_cvref_t&lt;decltype(X)&gt;&gt;</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>  struct constexpr_v;</span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>template &lt;class T&gt;</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>  concept <em>constexpr-param</em> =                                // <em>exposition only</em></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>    requires { typename constexpr_v&lt;T::value&gt;; } and not is_member_pointer_v&lt;decltype(&amp;T::value)&gt;;</span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>template &lt;class T&gt;</span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>  concept <em>derived-from-constexpr</em> =                         // <em>exposition only</em></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>    derived_from&lt;T, constexpr_v&lt;T::value&gt;&gt;;</span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a>template &lt;class T, class SelfT&gt;</span>
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>  concept <em>lhs-constexpr-param</em> =                            // <em>exposition only</em></span>
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>    <em>constexpr-param</em>&lt;T&gt; and (derived_from&lt;T, SelfT&gt; or not <em>derived-from-constexpr</em>&lt;T&gt;);</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>template&lt;auto X&gt;</span>
<span id="cb18-15"><a href="#cb18-15" aria-hidden="true" tabindex="-1"></a>  inline constexpr constexpr_v&lt;X&gt; c_;</span></code></pre></div>

</div>
<p>Add the following to [meta.help], after
<code class="sourceCode default">integral_constant</code>:</p>
<div class="add" style="color: #006e28">

<div class="sourceCode" id="cb19"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>template&lt;auto X, class T&gt;</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>struct constexpr_v {</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  using value_type = T;</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>  using type = constexpr_v;</span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>  constexpr operator value_type() const { return X; }</span>
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>  static constexpr value_type value = X;</span>
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>#if LEWG_SAYS_SO</span>
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>constexpr-param</em> U&gt;</span>
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a>    constexpr constexpr_v&lt;X = U::value&gt; operator=(U) const { return {}; }</span>
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>#endif</span>
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a>  template&lt;auto Y = X&gt;</span>
<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a>    constexpr auto operator+() const -&gt; constexpr_v&lt;+Y&gt; { return {}; }</span>
<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a>  template&lt;auto Y = X&gt;</span>
<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a>    constexpr auto operator-() const -&gt; constexpr_v&lt;-Y&gt; { return {}; }</span>
<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a>  template&lt;auto Y = X&gt;</span>
<span id="cb19-19"><a href="#cb19-19" aria-hidden="true" tabindex="-1"></a>    constexpr auto operator~() const -&gt; constexpr_v&lt;~Y&gt; { return {}; }</span>
<span id="cb19-20"><a href="#cb19-20" aria-hidden="true" tabindex="-1"></a>  template&lt;auto Y = X&gt;</span>
<span id="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a>    constexpr auto operator!() const -&gt; constexpr_v&lt;!Y&gt; { return {}; }</span>
<span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a>  template&lt;auto Y = X&gt;</span>
<span id="cb19-23"><a href="#cb19-23" aria-hidden="true" tabindex="-1"></a>    constexpr auto operator&amp;() const -&gt; constexpr_v&lt;&amp;Y&gt; { return {}; }</span>
<span id="cb19-24"><a href="#cb19-24" aria-hidden="true" tabindex="-1"></a>  template&lt;auto Y = X&gt;</span>
<span id="cb19-25"><a href="#cb19-25" aria-hidden="true" tabindex="-1"></a>    constexpr auto operator*() const -&gt; constexpr_v&lt;*Y&gt; { return {}; }</span>
<span id="cb19-26"><a href="#cb19-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-27"><a href="#cb19-27" aria-hidden="true" tabindex="-1"></a>  template&lt;class... Args&gt;</span>
<span id="cb19-28"><a href="#cb19-28" aria-hidden="true" tabindex="-1"></a>    constexpr auto operator()(Args... args) const -&gt; constexpr_v&lt;X(Args::value...)&gt; { return {}; }</span>
<span id="cb19-29"><a href="#cb19-29" aria-hidden="true" tabindex="-1"></a>  template&lt;class... Args&gt;</span>
<span id="cb19-30"><a href="#cb19-30" aria-hidden="true" tabindex="-1"></a>    constexpr auto operator[](Args... args) const -&gt; constexpr_v&lt;X[Args::value...]&gt; { return {}; }</span>
<span id="cb19-31"><a href="#cb19-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-32"><a href="#cb19-32" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-33"><a href="#cb19-33" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value + V::value&gt; operator+(U, V) { return {}; }</span>
<span id="cb19-34"><a href="#cb19-34" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-35"><a href="#cb19-35" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value - V::value&gt; operator-(U, V) { return {}; }</span>
<span id="cb19-36"><a href="#cb19-36" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-37"><a href="#cb19-37" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value * V::value&gt; operator*(U, V) { return {}; }</span>
<span id="cb19-38"><a href="#cb19-38" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-39"><a href="#cb19-39" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value / V::value&gt; operator/(U, V) { return {}; }</span>
<span id="cb19-40"><a href="#cb19-40" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-41"><a href="#cb19-41" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value % V::value&gt; operator%(U, V) { return {}; }</span>
<span id="cb19-42"><a href="#cb19-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-43"><a href="#cb19-43" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-44"><a href="#cb19-44" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &lt;&lt; V::value)&gt; operator&lt;&lt;(U, V) { return {}; }</span>
<span id="cb19-45"><a href="#cb19-45" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-46"><a href="#cb19-46" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &gt;&gt; V::value)&gt; operator&gt;&gt;(U, V) { return {}; }</span>
<span id="cb19-47"><a href="#cb19-47" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-48"><a href="#cb19-48" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value &amp; V::value&gt; operator&amp;(U, V) { return {}; }</span>
<span id="cb19-49"><a href="#cb19-49" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-50"><a href="#cb19-50" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value | V::value&gt; operator|(U, V) { return {}; }</span>
<span id="cb19-51"><a href="#cb19-51" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-52"><a href="#cb19-52" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value ^ V::value&gt; operator^(U, V) { return {}; }</span>
<span id="cb19-53"><a href="#cb19-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-54"><a href="#cb19-54" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-55"><a href="#cb19-55" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value &amp;&amp; V::value&gt; operator&amp;&amp;(U, V) { return {}; }</span>
<span id="cb19-56"><a href="#cb19-56" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-57"><a href="#cb19-57" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;U::value || V::value&gt; operator||(U, V) { return {}; }</span>
<span id="cb19-58"><a href="#cb19-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-59"><a href="#cb19-59" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-60"><a href="#cb19-60" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &lt;=&gt; V::value)&gt; operator&lt;=&gt;(U, V) { return {}; }</span>
<span id="cb19-61"><a href="#cb19-61" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-62"><a href="#cb19-62" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value == V::value)&gt; operator==(U, V) { return {}; }</span>
<span id="cb19-63"><a href="#cb19-63" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-64"><a href="#cb19-64" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value != V::value)&gt; operator!=(U, V) { return {}; }</span>
<span id="cb19-65"><a href="#cb19-65" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-66"><a href="#cb19-66" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &lt; V::value)&gt; operator&lt;(U, V) { return {}; }</span>
<span id="cb19-67"><a href="#cb19-67" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-68"><a href="#cb19-68" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &gt; V::value)&gt; operator&gt;(U, V) { return {}; }</span>
<span id="cb19-69"><a href="#cb19-69" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-70"><a href="#cb19-70" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &lt;= V::value)&gt; operator&lt;=(U, V) { return {}; }</span>
<span id="cb19-71"><a href="#cb19-71" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-72"><a href="#cb19-72" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &gt;= V::value)&gt; operator&gt;=(U, V) { return {}; }</span>
<span id="cb19-73"><a href="#cb19-73" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-74"><a href="#cb19-74" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-75"><a href="#cb19-75" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value, V::value)&gt; operator,(U, V) { return {}; }</span>
<span id="cb19-76"><a href="#cb19-76" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-77"><a href="#cb19-77" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value -&gt;* V::value)&gt; operator-&gt;*(U, V) { return {}; }</span>
<span id="cb19-78"><a href="#cb19-78" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-79"><a href="#cb19-79" aria-hidden="true" tabindex="-1"></a>#if LEWG_SAYS_SO</span>
<span id="cb19-80"><a href="#cb19-80" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-81"><a href="#cb19-81" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value += V::value)&gt; operator+=(U, V) { return {}; }</span>
<span id="cb19-82"><a href="#cb19-82" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-83"><a href="#cb19-83" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value -= V::value)&gt; operator-=(U, V) { return {}; }</span>
<span id="cb19-84"><a href="#cb19-84" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-85"><a href="#cb19-85" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value *= V::value)&gt; operator*=(U, V) { return {}; }</span>
<span id="cb19-86"><a href="#cb19-86" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-87"><a href="#cb19-87" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value /= V::value)&gt; operator/=(U, V) { return {}; }</span>
<span id="cb19-88"><a href="#cb19-88" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-89"><a href="#cb19-89" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value %= V::value)&gt; operator%=(U, V) { return {}; }</span>
<span id="cb19-90"><a href="#cb19-90" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-91"><a href="#cb19-91" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &amp;= V::value)&gt; operator&amp;=(U, V) { return {}; }</span>
<span id="cb19-92"><a href="#cb19-92" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-93"><a href="#cb19-93" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value |= V::value)&gt; operator|=(U, V) { return {}; }</span>
<span id="cb19-94"><a href="#cb19-94" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-95"><a href="#cb19-95" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value ^= V::value)&gt; operator^=(U, V) { return {}; }</span>
<span id="cb19-96"><a href="#cb19-96" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-97"><a href="#cb19-97" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &lt;&lt;= V::value)&gt; operator&lt;&lt;=(U, V) { return {}; }</span>
<span id="cb19-98"><a href="#cb19-98" aria-hidden="true" tabindex="-1"></a>  template &lt;<em>lhs-constexpr-param</em>&lt;type&gt; U, <em>constexpr-param</em> V&gt;</span>
<span id="cb19-99"><a href="#cb19-99" aria-hidden="true" tabindex="-1"></a>    friend constexpr constexpr_v&lt;(U::value &gt;&gt;= V::value)&gt; operator&gt;&gt;=(U, V) { return {}; }</span>
<span id="cb19-100"><a href="#cb19-100" aria-hidden="true" tabindex="-1"></a>#endif</span>
<span id="cb19-101"><a href="#cb19-101" aria-hidden="true" tabindex="-1"></a>};</span>
<span id="cb19-102"><a href="#cb19-102" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb19-103"><a href="#cb19-103" aria-hidden="true" tabindex="-1"></a>template&lt;auto X&gt;</span>
<span id="cb19-104"><a href="#cb19-104" aria-hidden="true" tabindex="-1"></a>  inline constexpr constexpr_v&lt;X&gt; c_{};</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
The class template <code class="sourceCode default">constexpr_v</code>
aids in metaprogramming by ensuring that the evaluation of expressions
comprised entirely of
<code class="sourceCode default">constexpr_v</code>s are core constant
expressions ([expr.const]), regardless of the context in which they
appear. In particular, this enables use of
<code class="sourceCode default">constexpr_v</code> values that are
passed as arguments to <code class="sourceCode default">constexpr</code>
functions to be used as template parameters.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
The variable template <code class="sourceCode default">c_</code> is
provided as a convenient way to nominate
<code class="sourceCode default">constexpr_v</code> values.</p>
</div>
<p>Add to [version.syn]:</p>
<div class="add" style="color: #006e28">

<div class="sourceCode" id="cb20"><pre class="sourceCode default default"><code class="sourceCode default"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>#define __cpp_lib_constexpr_v XXXXXXL // also in &lt;type_traits&gt;</span></code></pre></div>

</div>
</div>
</div>
</body>
</html>
