<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<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="2025-09-01" />
  <title>Hashing meta::info</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;

-webkit-text-size-adjust: none;
-moz-text-size-adjust: none;
text-size-adjust: none;
}
@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">Hashing meta::info</h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>
      P3816R0
      [<a href="https://wg21.link/P3816">Latest</a>]
      [<a href="https://wg21.link/P3816/status">Status</a>]
    </td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-09-01</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>
      SG7 Reflection<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Matt Cummins<br>&lt;<a href="mailto:mcummins16@bloomberg.net" class="email">mcummins16@bloomberg.net</a>&gt;<br>
      Valentyn Yukhymenko<br>&lt;<a href="mailto:vyuhimenko@bloomberg.net" class="email">vyuhimenko@bloomberg.net</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="#abstract" id="toc-abstract"><span class="toc-section-number">1</span> Abstract<span></span></a></li>
<li><a href="#motivation" id="toc-motivation"><span class="toc-section-number">2</span> Motivation<span></span></a></li>
<li><a href="#examples" id="toc-examples"><span class="toc-section-number">3</span> Examples<span></span></a>
<ul>
<li><a href="#mp11-mp_unique-using-reflection" id="toc-mp11-mp_unique-using-reflection"><span class="toc-section-number">3.1</span> Mp11
<code class="sourceCode cpp">mp_unique</code> using
reflection<span></span></a></li>
<li><a href="#custom-name_of-function" id="toc-custom-name_of-function"><span class="toc-section-number">3.2</span> Custom
<code class="sourceCode cpp">name_of</code>
function<span></span></a></li>
</ul></li>
<li><a href="#impact" id="toc-impact"><span class="toc-section-number">4</span> Impact<span></span></a>
<ul>
<li><a href="#on-the-standard" id="toc-on-the-standard"><span class="toc-section-number">4.1</span> On the
Standard<span></span></a></li>
<li><a href="#on-undefined-behavior" id="toc-on-undefined-behavior"><span class="toc-section-number">4.2</span> On undefined
behavior<span></span></a></li>
<li><a href="#on-existing-code" id="toc-on-existing-code"><span class="toc-section-number">4.3</span> On existing
code<span></span></a></li>
</ul></li>
<li><a href="#design-decisions" id="toc-design-decisions"><span class="toc-section-number">5</span> Design decisions<span></span></a>
<ul>
<li><a href="#the-api" id="toc-the-api"><span class="toc-section-number">5.1</span> The API<span></span></a>
<ul>
<li><a href="#hashmetainfo" id="toc-hashmetainfo"><span class="toc-section-number">5.1.1</span> <code class="sourceCode cpp">hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code><span></span></a></li>
<li><a href="#hash_of" id="toc-hash_of"><span class="toc-section-number">5.1.2</span>
<code class="sourceCode cpp">hash_of</code><span></span></a></li>
<li><a href="#consteval_hashmetainfo" id="toc-consteval_hashmetainfo"><span class="toc-section-number">5.1.3</span> <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code><span></span></a></li>
<li><a href="#alternate-names-for-consteval_hash" id="toc-alternate-names-for-consteval_hash"><span class="toc-section-number">5.1.4</span> Alternate names for
<code class="sourceCode cpp">consteval_hash</code><span></span></a></li>
</ul></li>
<li><a href="#ordered-maps-and-sets" id="toc-ordered-maps-and-sets"><span class="toc-section-number">5.2</span> Ordered maps and
sets<span></span></a></li>
</ul></li>
<li><a href="#proposed-wording" id="toc-proposed-wording"><span class="toc-section-number">6</span> Proposed wording<span></span></a>
<ul>
<li><a href="#the-specification-for-consteval_hasht" id="toc-the-specification-for-consteval_hasht"><span class="toc-section-number">6.1</span> The specification for <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code><span></span></a></li>
<li><a href="#the-specialization-for-metainfo" id="toc-the-specialization-for-metainfo"><span class="toc-section-number">6.2</span> The specialization for
<code class="sourceCode cpp">meta<span class="op">::</span>info</code><span></span></a></li>
<li><a href="#feature-testing-macros" id="toc-feature-testing-macros"><span class="toc-section-number">6.3</span> Feature testing
macros<span></span></a></li>
</ul></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">7</span> Implementation
experience<span></span></a></li>
<li><a href="#acknowledgements" id="toc-acknowledgements"><span class="toc-section-number">8</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">9</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" id="abstract"><span class="header-section-number">1</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>This paper proposes a new standard library template, <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
with a single specialization for
<code class="sourceCode cpp">meta<span class="op">::</span>info</code>.
The purpose of this facility is to provide a standard interface for
compile-time hashing, thereby allowing unordered containers such as
<code class="sourceCode cpp">unordered_map</code> and
<code class="sourceCode cpp">unordered_set</code> to be used with
<code class="sourceCode cpp">meta<span class="op">::</span>info</code>
keys, and potentially with other types in future.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> compile_time_function<span class="op">()</span> <span class="op">-&gt;</span> <span class="dt">void</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> <span class="kw">auto</span> hasher <span class="op">=</span> consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;{}</span>; <span class="co">// proposed</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> <span class="dt">size_t</span> h <span class="op">=</span> hasher<span class="op">(^^::)</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// now possible</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>    unordered_map<span class="op">&lt;</span>meta<span class="op">::</span>info, <span class="dt">int</span>, consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;&gt;</span> m;</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>    unordered_set<span class="op">&lt;</span>meta<span class="op">::</span>info, consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;&gt;</span>      s;</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="2" id="motivation"><span class="header-section-number">2</span> Motivation<a href="#motivation" class="self-link"></a></h1>
<p><span class="citation" data-cites="P2996"><a href="https://isocpp.org/files/papers/P2996R13.html" role="doc-biblioref">[P2996]</a></span> introduces
<code class="sourceCode cpp">meta<span class="op">::</span>info</code>
to represent reflections of C++ constructs. However, hashing support was
intentionally omitted, as it is not a core reflection feature.</p>
<p><span class="citation" data-cites="P3372"><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3372r3.html" role="doc-biblioref">[P3372]</a></span> makes unordered containers
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>,
which creates demand for compile-time hashing in order to use
<code class="sourceCode cpp">meta<span class="op">::</span>info</code>
and other consteval-only types as keys.</p>
<p>A straightforward approach would be to specialize <code class="sourceCode cpp">hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code>,
but <code class="sourceCode cpp">hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
in general is not constexpr-friendly due to its runtime requirements.
This paper therefore proposes a dedicated facility for compile-time
hashing.</p>
<h1 data-number="3" id="examples"><span class="header-section-number">3</span> Examples<a href="#examples" class="self-link"></a></h1>
<p>The following examples illustrate practical applications of
<code class="sourceCode cpp">consteval_hash</code>.</p>
<h2 data-number="3.1" id="mp11-mp_unique-using-reflection"><span class="header-section-number">3.1</span> Mp11
<code class="sourceCode cpp">mp_unique</code> using reflection<a href="#mp11-mp_unique-using-reflection" class="self-link"></a></h2>
<p>In <span class="citation" data-cites="P2830"><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2830r10.html" role="doc-biblioref">[P2830]</a></span> (7.3) the authors discuss the
infeasibility of implementing
<code class="sourceCode cpp">mp_unique</code> using value-based
reflection. Our proposal provides a short and effective solution without
needing to sort a list of reflected types.</p>
<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">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">...</span> Types<span class="op">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> type_list <span class="op">{}</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> TypeList<span class="op">&gt;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">consteval</span> <span class="kw">auto</span> mp_unique_reflected<span class="op">()</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>meta<span class="op">::</span>has_template_arguments<span class="op">(^^</span>TypeList<span class="op">)</span>, <span class="st">&quot;mp_unique requires a type_list&quot;</span><span class="op">)</span>;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>meta<span class="op">::</span>template_of<span class="op">(^^</span>TypeList<span class="op">)</span> <span class="op">==</span> <span class="op">^^</span>type_list, <span class="st">&quot;mp_unique requires a type_list&quot;</span><span class="op">)</span>;</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>    unordered_set<span class="op">&lt;</span>meta<span class="op">::</span>info, consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;&gt;</span> seen;</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    vector<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span> unique_types;</span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span> <span class="op">(</span><span class="kw">auto</span> type_info <span class="op">:</span> meta<span class="op">::</span>template_arguments_of<span class="op">(^^</span>TypeList<span class="op">))</span> <span class="op">{</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>        <span class="cf">if</span> <span class="op">(</span><span class="kw">const</span> <span class="dt">bool</span> is_unique <span class="op">=</span> seen<span class="op">.</span>insert<span class="op">(</span>type_info<span class="op">).</span>second; is_unique<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>            unique_types<span class="op">.</span>push_back<span class="op">(</span>type_info<span class="op">)</span>;</span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> meta<span class="op">::</span>substitute<span class="op">(^^</span>type_list, unique_types<span class="op">)</span>;</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> TypeList<span class="op">&gt;</span></span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> mp_unique <span class="op">=</span> <span class="op">[:</span>mp_unique_reflected<span class="op">&lt;</span>TypeList<span class="op">&gt;():]</span>;</span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> input <span class="op">=</span> type_list<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">char</span>, <span class="dt">int</span>, string, <span class="dt">double</span>, <span class="dt">char</span><span class="op">&gt;</span>;</span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> filtered <span class="op">=</span> mp_unique<span class="op">&lt;</span>input<span class="op">&gt;</span>;</span>
<span id="cb2-27"><a href="#cb2-27" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> expected <span class="op">=</span> type_list<span class="op">&lt;</span><span class="dt">int</span>, <span class="dt">char</span>, string, <span class="dt">double</span><span class="op">&gt;</span>;</span>
<span id="cb2-28"><a href="#cb2-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-29"><a href="#cb2-29" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>is_same_v<span class="op">&lt;</span>expected, filtered<span class="op">&gt;)</span>;</span></code></pre></div>
<h2 data-number="3.2" id="custom-name_of-function"><span class="header-section-number">3.2</span> Custom
<code class="sourceCode cpp">name_of</code> function<a href="#custom-name_of-function" class="self-link"></a></h2>
<p>In <span class="citation" data-cites="P2996"><a href="https://isocpp.org/files/papers/P2996R13.html" role="doc-biblioref">[P2996]</a></span> (4.4.6), the authors discuss the
challenges of producing user-friendly names for reflected entities and
argue that functions such as <code class="sourceCode cpp">name_of</code>
should be implemented by third-party C++ libraries rather than
standardized, with the standard providing the necessary lower level
tools to do so. To implement such a function, one might define a custom
mapping of known types or entities to more descriptive labels.</p>
<p>Using <code class="sourceCode cpp">unordered_map</code> for the
mapping provides a terser implementation:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Without map</strong>
</div></th>
<th><div style="text-align:center">
<strong>With map</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<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">consteval</span> name_of<span class="op">(</span>meta<span class="op">::</span>info r<span class="op">)</span> <span class="op">-&gt;</span> string_view</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>r <span class="op">==</span> <span class="op">^^</span><span class="dt">int</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="st">&quot;integer&quot;</span>;</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>r <span class="op">==</span> <span class="op">^^</span><span class="dt">float</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="st">&quot;32-bit float&quot;</span>;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>r <span class="op">==</span> <span class="op">^^</span><span class="dt">double</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="st">&quot;64-bit float&quot;</span>;</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="cf">if</span> <span class="op">(</span>r <span class="op">==</span> <span class="op">^^</span><span class="dt">bool</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="st">&quot;boolean&quot;</span>;</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>r <span class="op">==</span> <span class="op">^^</span><span class="dt">unsigned</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="st">&quot;unsigned integer&quot;</span>;</span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>r <span class="op">==</span> <span class="op">^^::)</span> <span class="op">{</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="st">&quot;global namespace&quot;</span>;</span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>r <span class="op">==</span> <span class="op">^^</span>MyType<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="st">&quot;my library type&quot;</span>;</span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true" tabindex="-1"></a>    <span class="co">// add more as required</span></span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Fall back to identifier if it exists</span></span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>meta<span class="op">::</span>has_identifier<span class="op">(</span>r<span class="op">))</span> <span class="op">{</span></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> meta<span class="op">::</span>identifier_of<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb3-30"><a href="#cb3-30" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span>;</span>
<span id="cb3-31"><a href="#cb3-31" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

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

<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">consteval</span> name_of<span class="op">(</span>meta<span class="op">::</span>info r<span class="op">)</span> <span class="op">-&gt;</span> string_view</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>    unordered_map<span class="op">&lt;</span>meta<span class="op">::</span>info, string_view, consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;&gt;</span> names <span class="op">=</span> <span class="op">{</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>        <span class="op">{^^</span><span class="dt">int</span>,      <span class="st">&quot;integer&quot;</span><span class="op">}</span>,</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>        <span class="op">{^^</span><span class="dt">float</span>,    <span class="st">&quot;32-bit float&quot;</span><span class="op">}</span>,</span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>        <span class="op">{^^</span><span class="dt">double</span>,   <span class="st">&quot;64-bit float&quot;</span><span class="op">}</span>,</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>        <span class="op">{^^</span><span class="dt">bool</span>,     <span class="st">&quot;boolean&quot;</span><span class="op">}</span>,</span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>        <span class="op">{^^</span><span class="dt">unsigned</span>, <span class="st">&quot;unsigned integer&quot;</span><span class="op">}</span>,</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">{^^::</span>,       <span class="st">&quot;global namespace&quot;</span><span class="op">}</span>,</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>        <span class="op">{^^</span>MyType,   <span class="st">&quot;my library type&quot;</span><span class="op">}</span>,</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>        <span class="co">// add more as required</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>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span><span class="kw">auto</span> it <span class="op">=</span> names<span class="op">.</span>find<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>        it <span class="op">!=</span> names<span class="op">.</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> it<span class="op">-&gt;</span>second;</span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>    <span class="co">// Fall back to identifier if it exists</span></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> <span class="op">(</span>meta<span class="op">::</span>has_identifier<span class="op">(</span>r<span class="op">))</span> <span class="op">{</span></span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> meta<span class="op">::</span>identifier_of<span class="op">(</span>r<span class="op">)</span>;</span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="st">&quot;&lt;unnamed&gt;&quot;</span>;</span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<h1 data-number="4" id="impact"><span class="header-section-number">4</span> Impact<a href="#impact" class="self-link"></a></h1>
<h2 data-number="4.1" id="on-the-standard"><span class="header-section-number">4.1</span> On the Standard<a href="#on-the-standard" class="self-link"></a></h2>
<p>This proposal is a pure library addition and does not depend on any
other library extensions. It introduces the first example of a
compile-time hash facility. Moreover, it enables future standard library
features: new
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
functions may naturally require unordered containers as part of their
interfaces, and <code class="sourceCode cpp">consteval_hash</code>
provides the uniform mechanism needed to support such APIs.</p>
<h2 data-number="4.2" id="on-undefined-behavior"><span class="header-section-number">4.2</span> On undefined behavior<a href="#on-undefined-behavior" class="self-link"></a></h2>
<p>This proposal applies only to compile-time programming, where
undefined behavior is disallowed. Accordingly, it does not introduce
additional undefined behavior into the standard.</p>
<h2 data-number="4.3" id="on-existing-code"><span class="header-section-number">4.3</span> On existing code<a href="#on-existing-code" class="self-link"></a></h2>
<p>As this is a new type in the <code class="sourceCode cpp">std</code>
namespace, this change does not break any existing code, except in the
unlikely event that a user has added their own
<code class="sourceCode cpp">consteval_hash</code> type to
<code class="sourceCode cpp">std</code>, which is already undefined
behavior.</p>
<h1 data-number="5" id="design-decisions"><span class="header-section-number">5</span> Design decisions<a href="#design-decisions" class="self-link"></a></h1>
<h2 data-number="5.1" id="the-api"><span class="header-section-number">5.1</span> The API<a href="#the-api" class="self-link"></a></h2>
<h3 data-number="5.1.1" id="hashmetainfo"><span class="header-section-number">5.1.1</span> <code class="sourceCode cpp">hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code><a href="#hashmetainfo" class="self-link"></a></h3>
<p>Ultimately, the goal of this paper is to provide a robust way to hash
values of type <code class="sourceCode cpp">meta<span class="op">::</span>info<span class="op">.</span></code>
The most “obvious” way to do this is to implement <code class="sourceCode cpp">hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code>,
however this introduces inconsistencies:</p>
<ul>
<li>Because of the runtime requirements on <code class="sourceCode cpp">hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
existing specializations cannot be made
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>,
meaning we would end up with some specializations of <code class="sourceCode cpp">std<span class="op">::</span>hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
being consteval-only, while others are runtime-only.</li>
<li>This then makes using the unordered containers at compile-time
inconsistent; depending on the key type, you would sometimes be able to
use the default hash, while with others you would need to use
another.</li>
<li>When looking at some code involving the unordered containers,
readers would not be able to tell just from the code whether the hash is
runtime-only or compile-time-only, and would have to look back at the
definition of hash. Having a distinct type so that hash is always
runtime-only solves this.</li>
</ul>
<h3 data-number="5.1.2" id="hash_of"><span class="header-section-number">5.1.2</span>
<code class="sourceCode cpp">hash_of</code><a href="#hash_of" class="self-link"></a></h3>
<p>We could sidestep the issues associated with <code class="sourceCode cpp">hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code>
by instead providing a free function:</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">namespace</span> std<span class="op">::</span>meta <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> hash_of<span class="op">(</span>info r<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">size_t</span>;</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This would be defined in <code class="sourceCode cpp"><span class="op">&lt;</span>meta<span class="op">&gt;</span></code>.
If users need to use
<code class="sourceCode cpp">meta<span class="op">::</span>info</code>
as keys in compile-time hash maps, they can use it to implement their
own hash (like they will have to do with all other types currently).
However, we do not propose this because:</p>
<ul>
<li>The functions in <code class="sourceCode cpp"><span class="op">&lt;</span>meta<span class="op">&gt;</span></code>
provide fundamental details about reflections, and having a
<code class="sourceCode cpp">hash_of</code> function suggests there is a
single meaningful way of hashing which is obviously not true. <code class="sourceCode cpp">hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
solves this by simply being understood to provide <em>a</em> reasonable
default implementation, not <em>the</em> implementation.
<ul>
<li>The caveat here is that this is not quite true; <code class="sourceCode cpp"><span class="op">&lt;</span>meta<span class="op">&gt;</span></code>
also provides <code class="sourceCode cpp">display_string_of</code>,
which provides some reasonable string representation of the given
reflection. But aside from this single function, the point still
holds.</li>
</ul></li>
<li>More crucially, if we provide users with functionality that they
need to wrap themselves, we should just standardize the boilerplate
instead. Which leads to…</li>
</ul>
<h3 data-number="5.1.3" id="consteval_hashmetainfo"><span class="header-section-number">5.1.3</span> <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code><a href="#consteval_hashmetainfo" class="self-link"></a></h3>
<p>This brings us to the proposal in this paper. It has a few
benefits:</p>
<ul>
<li>It is similar to <code class="sourceCode cpp">hash_of</code>, but
does not have the same drawback of suggesting that it is the single
meaningful way to hash
<code class="sourceCode cpp">meta<span class="op">::</span>info</code>.
It carries the same semantics of a “reasonable implementation” that
<code class="sourceCode cpp">hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
has.</li>
<li>Users won’t need to write their own wrapper of
<code class="sourceCode cpp">hash_of</code>.</li>
<li>Even if <code class="sourceCode cpp">hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
could be made constexpr for other types (which it can’t), there would
still be an issue with value consistency between runtime and
compile-time for pointers, and possibly other types. Separating runtime
and compile-time hashing into two separate types avoids this issue, as
you shouldn’t expect two hashing algorithms to give the same result.
<ul>
<li>Because of this, with a new type you could easily provide <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>T<span class="op">*&gt;</span></code>
as well.</li>
</ul></li>
<li>It can be easily extended for all other standard and builtin types
that have a specialization of hash, making compile-time map usage far
more uniform.</li>
</ul>
<p>It also has a few obvious downsides:</p>
<ul>
<li>Whenever a new specialization of <code class="sourceCode cpp">hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
is standardized, it likely will also want a corresponding <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>,
increasing the burden on implementers.</li>
<li>When users implement <code class="sourceCode cpp">hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
for their own type, they may not care about hash salting and just
implement their <code class="sourceCode cpp">hash<span class="op">&lt;</span>T<span class="op">&gt;::</span><span class="kw">operator</span><span class="op">()</span></code>
as
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>,
which is more natural than also implementing
<code class="sourceCode cpp">consteval_hash</code> and easier to use.
However, this is unlikely to be a significant concern for the
standard.</li>
<li>The use of unordered containers in
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
functions remains awkward. Different types are required at compile-time
versus runtime, often necessitating heavy use of <code class="sourceCode cpp"><span class="cf">if</span> <span class="kw">consteval</span></code>.
However, this is already a problem, and this proposal is not intended to
address it.</li>
</ul>
<p>Overall, this feels like the more complete and extensible solution,
so it is the one we are proposing.</p>
<h3 data-number="5.1.4" id="alternate-names-for-consteval_hash"><span class="header-section-number">5.1.4</span> Alternate names for
<code class="sourceCode cpp">consteval_hash</code><a href="#alternate-names-for-consteval_hash" class="self-link"></a></h3>
<p>There are a few other names we considered. Below is a list of them as
well as the reasons we decided against them.</p>
<table>
<colgroup>
<col style="width: 32%" />
<col style="width: 67%" />
</colgroup>
<tbody>
<tr class="odd">
<td>Name</td>
<td>Comments</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">stable_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>This name would be better suited to a
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
hash usable at both runtime and compile-time. To us, this name does not
capture the core feature of the proposed hash, that is to be
compile-time only. Our specification for the new type also does not
guarantee stability across translation units, so this name is
misleading.</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">static_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>The keyword static in C++ already means “compile-time” in some
cases, e.g. <code class="sourceCode cpp"><span class="kw">static_assert</span></code>,
however the keyword is overloaded with many other meanings, so could be
confusing. consteval is the keyword for compile-time, hence
<code class="sourceCode cpp">consteval_hash</code>.</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">meta_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>Concise and clearly related to compile-time functionality. However,
the word “meta” more closely relates to reflection, which is a subset of
compile-time functionality, and one which compile-time hashing does not
necessarily have anything to do with.</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">fixed_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>Similar to <code class="sourceCode cpp">stable_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
in meaning.</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">compile_time_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>This name best describes what it does, but given that C++ already
has the
<code class="sourceCode cpp"><span class="kw">consteval</span></code>
keyword to mean “compile-time-only”, this name is less consistent with
the rest of the language.</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">comptime_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>Although we love Zig, we are proposing a C++ feature!</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">ct_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>Terse, but too terse. Would you guess that it was a shortening of
“compile-time hash” at first glance?</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">ce_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>Same as above. Would you guess it was a shortening of “consteval
hash”?</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">compile_time_only_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>Consistent with
<code class="sourceCode cpp">move_only_function</code>, but far too
long.</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">consteval_only_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>A slight improvement on the above, but the “only” is superfluous
since consteval already denotes that it only works at compile-time.</td>
</tr>
<tr class="even">
<td><code class="sourceCode cpp">constexpr_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code></td>
<td>Just incorrect, implies that it is usable at runtime too. If such a
type existed, you would expect its interface to be made up of
<code class="sourceCode cpp"><span class="kw">constexpr</span></code>
functions, not
<code class="sourceCode cpp"><span class="kw">consteval</span></code>.</td>
</tr>
<tr class="odd">
<td><code class="sourceCode cpp">hash<span class="op">&lt;</span>T, hashtype<span class="op">::</span>compile_time<span class="op">&gt;</span></code></td>
<td>Rather than a new type, we could instead extend <code class="sourceCode cpp">hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code>
by providing an enum class to select what kind of hash you want. This
enum could be extended to provide even more hashes in the future. This
feels far messier, and given that it would be impossible to implement
certain hashes for certain types, it would be misleading and provide an
API that looks incomplete.</td>
</tr>
</tbody>
</table>
<h2 data-number="5.2" id="ordered-maps-and-sets"><span class="header-section-number">5.2</span> Ordered maps and sets<a href="#ordered-maps-and-sets" class="self-link"></a></h2>
<p>Given that this proposal focuses on enabling unordered maps and sets
keyed on
<code class="sourceCode cpp">meta<span class="op">::</span>info</code>,
it is natural to also ask what meaning, if any, should be assigned to
<code class="sourceCode cpp">map<span class="op">&lt;</span>meta<span class="op">::</span>info, T<span class="op">&gt;</span></code>
and <code class="sourceCode cpp">set<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code>.
Both of these would require <code class="sourceCode cpp">less<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code>
to be well-defined, which would require <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;</span></code>
to be defined. There is no meaningful natural ordering for reflections,
but we discussed a couple of options here:</p>
<ul>
<li>A naive approach would be to implement <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;</span></code>
in terms of <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code>,
but the issue is that distinct reflections are not guaranteed to have
distinct hashes. The ordering would change every time the hash does as
well.</li>
<li>A better approach would be to define <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;</span></code>
in the same way that it is defined for pointers, which is done via an
implementation defined strict total ordering, with no guarantees given
on the consistency of ordering between runs.</li>
</ul>
<p>Regardless of how <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;</span></code>
is implemented, an explicit specialization for <code class="sourceCode cpp">less<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></code>
would still be required in order to make it a consteval-only type.</p>
<p>In addition to that, <span class="citation" data-cites="P2830"><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2830r10.html" role="doc-biblioref">[P2830]</a></span> (4.1.4) states that any <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">&lt;=&gt;</span></code>
defined for <code class="sourceCode cpp">std<span class="op">::</span>meta<span class="op">::</span>info</code>
should be consistent with compile-time type ordering it proposes.</p>
<p>Ultimately this seems like a harder problem and we intentionally
leave this out of scope, restricting this paper to hashing.</p>
<h1 data-number="6" id="proposed-wording"><span class="header-section-number">6</span> Proposed wording<a href="#proposed-wording" class="self-link"></a></h1>
<h2 data-number="6.1" id="the-specification-for-consteval_hasht"><span class="header-section-number">6.1</span> The specification for <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>T<span class="op">&gt;</span></code><a href="#the-specification-for-consteval_hasht" class="self-link"></a></h2>
<p>Add a new section, <code class="sourceCode cpp">ConstevalHash</code>
[constevalhash.requirements], defined analogously to
<code class="sourceCode cpp">Cpp17Hash</code> [hash.requirements]:</p>
<div class="add" style="color: #006e28">

<blockquote>
<p>A type <code class="sourceCode default">H</code> meets the
<code class="sourceCode default">ConstevalHash</code> requirements
if</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">1</a></span> It is a
function object type ([function.objects]).</li>
<li><span class="marginalizedparent"><a class="marginalized">2</a></span> It meets
the <code class="sourceCode default">Cpp17CopyConstructible</code> and
<code class="sourceCode default">Cpp17Destructible</code>
requirements.</li>
<li><span class="marginalizedparent"><a class="marginalized">3</a></span> It is a
consteval-only type ([basic.types.general]).</li>
<li><span class="marginalizedparent"><a class="marginalized">4</a></span> Given
two instances of H, it is not guaranteed that they will produce the same
values for the same arguments.
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<span class="note"><span>[ <em>Note:</em> </span>In particular, the
values may be different between translation units.<span> — <em>end
note</em> ]</span></span></li>
</ul></li>
<li><span class="marginalizedparent"><a class="marginalized">5</a></span> The
expressions in the table below are valid and have the indicated
semantics:</li>
</ul>
<p>Given <code class="sourceCode default">Key</code> is an argument type
for function objects of type <code class="sourceCode default">H</code>,
<code class="sourceCode default">h</code> is a value of type (possibly
<code class="sourceCode default">const</code>)
<code class="sourceCode default">H</code>,
<code class="sourceCode default">u</code> is an lvalue of type
<code class="sourceCode default">Key</code>, and
<code class="sourceCode default">k</code> is a value of type convertible
to (possibly <code class="sourceCode default">const</code>)
<code class="sourceCode default">Key</code>.</p>
<table>
<colgroup>
<col style="width: 17%" />
<col style="width: 13%" />
<col style="width: 68%" />
</colgroup>
<tbody>
<tr class="odd">
<td>Expression</td>
<td>Return type</td>
<td>Requirement</td>
</tr>
<tr class="even">
<td><code class="sourceCode default">h(k)</code></td>
<td><code class="sourceCode default">size_t</code></td>
<td><p>The value returned shall depend only on
<code class="sourceCode default">k</code>.</p>
<p>The value shall be stable across repeated compiler runs. <span class="note"><span>[ <em>Note:</em> </span>Modifying the source code may
change the value.<span> — <em>end note</em> ]</span></span></p>
<p>For two different values <code class="sourceCode default">t1</code>
and <code class="sourceCode default">t2</code>, the probability that
<code class="sourceCode default">h(t1)</code> and
<code class="sourceCode default">h(t2)</code> compare equal should be
very small, approaching <code class="sourceCode default">1.0 / numeric_limits&lt;size_t&gt;::max()</code>.</p></td>
</tr>
<tr class="odd">
<td><code class="sourceCode default">h(u)</code></td>
<td><code class="sourceCode default">size_t</code></td>
<td>Shall not modify <code class="sourceCode default">u</code>.</td>
</tr>
</tbody>
</table>
</blockquote>

</div>
<p>Add a new section, “Class template consteval_hash”
[unord.consteval_hash], defined analogously to “Class template hash”
[unord.hash]. The only difference is that this currently makes no
mention of specializations for
<code class="sourceCode cpp">nullptr_t</code> or for cv-unqualified
arithmetic, enumeration and pointer types (which can be added
later):</p>
<div class="add" style="color: #006e28">

<blockquote>
<p>Class
<code class="sourceCode default">template consteval_hash</code></p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">1</a></span> Each
specialization of <code class="sourceCode default">consteval_hash</code>
is either enabled or disabled, as described below.
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<span class="note"><span>[ <em>Note:</em> </span>Enabled specializations
meet the <code class="sourceCode default">ConstevalHash</code>
requirements, and disabled specializations do not.<span> — <em>end
note</em> ]</span></span></li>
</ul></li>
<li><span class="marginalizedparent"><a class="marginalized">2</a></span> If the
library provides an explicit or partial specialization of
<code class="sourceCode default">consteval_hash&lt;Key&gt;</code>, that
specialization is enabled except as noted otherwise, and its member
functions are <code class="sourceCode default">noexcept</code> except as
noted otherwise.</li>
<li><span class="marginalizedparent"><a class="marginalized">3</a></span> If
<code class="sourceCode default">H</code> is a disabled specialization
of <code class="sourceCode default">consteval_hash</code>, these values
are <code class="sourceCode default">false</code>: <code class="sourceCode default">is_default_constructible_v&lt;H&gt;</code>,
<code class="sourceCode default">is_copy_constructible_v&lt;H&gt;</code>,
<code class="sourceCode default">is_copy_assignable_v&lt;H&gt;</code>,
and
<code class="sourceCode default">is_move_assignable_v&lt;H&gt;</code>.
Disabled specializations of
<code class="sourceCode default">consteval_hash</code>&gt; {.cpp} are
not function object types ([function.objects]).
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<span class="note"><span>[ <em>Note:</em> </span>This means that the
specialization of consteval_hash exists, but any attempts to use it as a
ConstevalHash will be ill-formed.<span> — <em>end note</em>
]</span></span></li>
</ul></li>
<li><span class="marginalizedparent"><a class="marginalized">4</a></span> An
enabled specialization
<code class="sourceCode default">consteval_hash&lt;Key&gt;</code> will:
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> Meet
the <code class="sourceCode default">ConstevalHash</code> requirements,
with <code class="sourceCode default">Key</code> as the function call
argument type, the
<code class="sourceCode default">Cpp17DefaultConstructible</code>
requirements, the
<code class="sourceCode default">Cpp17CopyAssignable</code>
requirements, the <code class="sourceCode default">Cpp17Swappable</code>
requirements.</li>
<li><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> Meet
the requirement that if <code class="sourceCode default">k1 == k2</code>
is <code class="sourceCode default">true</code>,
<code class="sourceCode default">h(k1) == h(k2)</code> is also
<code class="sourceCode default">true</code>, where h is an object of
type <code class="sourceCode default">consteval_hash&lt;Key&gt;</code>
and <code class="sourceCode default">k1</code> and
<code class="sourceCode default">k2</code> are objects of type Key.</li>
<li><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span> Meet
the requirement that the expression
<code class="sourceCode default">h(k)</code>, where
<code class="sourceCode default">h</code> is an object of type
<code class="sourceCode default">consteval_hash&lt;Key&gt;</code> and
<code class="sourceCode default">k</code> is an object of type
<code class="sourceCode default">Key</code>, shall not throw an
exception unless
<code class="sourceCode default">consteval_hash&lt;Key&gt;</code> is a
program-defined specialization.</li>
</ul></li>
</ul>
</blockquote>

</div>
<h2 data-number="6.2" id="the-specialization-for-metainfo"><span class="header-section-number">6.2</span> The specialization for
<code class="sourceCode cpp">meta<span class="op">::</span>info</code><a href="#the-specialization-for-metainfo" class="self-link"></a></h2>
<p>Add a new section [meta.reflection.hash]:</p>
<div class="add" style="color: #006e28">

<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>template &lt;typename T&gt; struct consteval_hash;</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>template &lt;&gt; struct consteval_hash&lt;meta::info&gt;;</span></code></pre></div>
<p>The specialization is enabled ([unord.consteval_hash]).</p>
</blockquote>

</div>
<h2 data-number="6.3" id="feature-testing-macros"><span class="header-section-number">6.3</span> Feature testing macros<a href="#feature-testing-macros" class="self-link"></a></h2>
<p>Add two new feature macros into <a href="https://eel.is/c++draft/version.syn">[version.syn]</a>, one for
the new type, and one for the
<code class="sourceCode cpp">meta<span class="op">::</span>info</code>
instantiation:</p>
<div class="add" style="color: #006e28">

<blockquote>
<div class="sourceCode" id="cb7"><pre class="sourceCode default cpp"><code class="sourceCode default"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>#define __lib_consteval_hash_template YYYYXXL  // also in &lt;meta&gt;</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>#define __lib_consteval_hash_meta_info YYYYXXL // also in &lt;meta&gt;</span></code></pre></div>
</blockquote>

</div>
<h1 data-number="7" id="implementation-experience"><span class="header-section-number">7</span> Implementation experience<a href="#implementation-experience" class="self-link"></a></h1>
<p>We <a href="https://github.com/bloomberg/clang-p2996/pull/170">implemented</a>
this on a branch of Bloomberg’s Clang fork. Like with the rest of the
reflection API, <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;::</span><span class="kw">operator</span><span class="op">()</span></code>
can be implemented via a compiler intrinsic.</p>
<p>Our initial implementation was unstable across repeated runs due to
it hashing pointers under the hood, but was simple. To implement a hash
that was stable across repeated compiler runs, we assigned each
<code class="sourceCode cpp">Type</code> a unique ID which made hashing
type reflections stable. For most other reflections, we were able to
define the hash based on their source locations which were also stable.
Naturally, the values change if code is moved or new type definitions
are added, but this still satisfies the requirement of not breaking
repeat builds.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">consteval</span> consteval_hash<span class="op">()</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">consteval</span> consteval_hash<span class="op">(</span><span class="kw">const</span> consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">consteval</span> consteval_hash<span class="op">(</span>consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;&amp;&amp;)</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">consteval</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">()(</span>meta<span class="op">::</span>info r<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">-&gt;</span> <span class="dt">size_t</span> <span class="op">{</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> __metafunction<span class="op">(</span>meta<span class="op">::</span>detail<span class="op">::</span>__metafn_reflection_hash, r<span class="op">)</span>;</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>  <span class="co">// This unused variable is here to make consteval_hash&lt;&gt; a</span></span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>  <span class="co">// consteval-only type.</span></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>  <span class="op">[[</span><span class="at">maybe_unused</span><span class="op">]]</span> <span class="kw">const</span> meta<span class="op">::</span>info unused <span class="op">=</span> <span class="op">^^::</span>;</span>
<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>A simpler alternative would be to hash the display strings associated
with each reflection, for example using <code class="sourceCode cpp">meta<span class="op">::</span>display_string_of</code>
or a similar function. However there is no guarantee that this function
provides good quality names that can provide a quality hash, but this
would produce values that are far more stable, including across
translation units.</p>
<p><span class="citation" data-cites="P3068"><a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3068r2.html" role="doc-biblioref">[P3068]</a></span> has been approved for C++26,
allowing exception throwing within constexpr, so it is meaningful to
mark <code class="sourceCode cpp">consteval_hash<span class="op">&lt;</span>meta<span class="op">::</span>info<span class="op">&gt;::</span><span class="kw">operator</span><span class="op">()</span></code>
as
<code class="sourceCode cpp"><span class="kw">noexcept</span></code>.</p>
<h1 data-number="8" id="acknowledgements"><span class="header-section-number">8</span> Acknowledgements<a href="#acknowledgements" class="self-link"></a></h1>
<ul>
<li>Dan Katz for the original implementation and wording, as well as his
work on implementing the main reflection paper in Clang.</li>
<li>Hana Dusíková for allowing unordered containers to be usable in
constexpr, which is a primary motivator for this paper.</li>
</ul>
<h1 data-number="9" id="bibliography"><span class="header-section-number">9</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-P2830" class="csl-entry" role="doc-biblioentry">
[P2830] Nate Nichols and Gašper Ažman. Constexpr Type Ordering. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2830r10.html"><div class="csl-block">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2830r10.html</div></a>
</div>
<div id="ref-P2996" class="csl-entry" role="doc-biblioentry">
[P2996] Wyatt Childers, Peter Dimov, Dan Katz, Barry Revzin, Andrew
Sutton, Faisal Vali, and Daveed Vandevoorde. Reflection for C++. <a href="https://isocpp.org/files/papers/P2996R13.html"><div class="csl-block">https://isocpp.org/files/papers/P2996R13.html</div></a>
</div>
<div id="ref-P3068" class="csl-entry" role="doc-biblioentry">
[P3068] Hana Dusíková. Allowing Exception Throwing in
Constant-Evaluation. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3068r2.html"><div class="csl-block">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3068r2.html</div></a>
</div>
<div id="ref-P3372" class="csl-entry" role="doc-biblioentry">
[P3372] Hana Dusíková. Constexpr Containers and Adaptors. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3372r3.html"><div class="csl-block">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3372r3.html</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
