<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<meta name="author" content="Hana+Dus%C3%ADkov%C3%A1">
	<meta name="description" content="Constexpr exception thrown in a constraint check (concept) means the check is false, and compiler can use .what()&#039;s result as a nice error message.">
	<meta name="generator" content="hatemplate/v2">
	<title>P3679R0: SFINAEable constexpr exceptions</title>
	
	<link rel="preconnect" href="https://fonts.googleapis.com">
	<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
	
	
<!-- highlight.min.js -->
<script>
/*!
  Highlight.js v11.9.0 (git: b7ec4bfafc)
  (c) 2006-2024 undefined and other contributors
  License: BSD-3-Clause
 */
var hljs=function(){"use strict";function e(t){
return t instanceof Map?t.clear=t.delete=t.set=()=>{
throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{
throw Error("set is read-only")
}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{
const i=t[n],s=typeof i;"object"!==s&&"function"!==s||Object.isFrozen(i)||e(i)
})),t}class t{constructor(e){
void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
ignoreMatch(){this.isMatchIgnored=!0}}function n(e){
return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")
}function i(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const s=e=>!!e.scope
;class o{constructor(e,t){
this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
this.buffer+=n(e)}openNode(e){if(!s(e))return;const t=((e,{prefix:t})=>{
if(e.startsWith("language:"))return e.replace("language:","language-")
;if(e.includes(".")){const n=e.split(".")
;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ")
}return`${t}${e}`})(e.scope,{prefix:this.classPrefix});this.span(t)}
closeNode(e){s(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
this.buffer+=`<span class="${e}">`}}const r=(e={})=>{const t={children:[]}
;return Object.assign(t,e),t};class a{constructor(){
this.rootNode=r(),this.stack=[this.rootNode]}get top(){
return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
this.top.children.push(e)}openNode(e){const t=r({scope:e})
;this.add(t),this.stack.push(t)}closeNode(){
if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){
return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
a._collapse(e)})))}}class c extends a{constructor(e){super(),this.options=e}
addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){
this.closeNode()}__addSublanguage(e,t){const n=e.root
;t&&(n.scope="language:"+t),this.add(n)}toHTML(){
return new o(this,this.options).value()}finalize(){
return this.closeAllNodes(),!0}}function l(e){
return e?"string"==typeof e?e:e.source:null}function g(e){return h("(?=",e,")")}
function u(e){return h("(?:",e,")*")}function d(e){return h("(?:",e,")?")}
function h(...e){return e.map((e=>l(e))).join("")}function f(...e){const t=(e=>{
const t=e[e.length-1]
;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{}
})(e);return"("+(t.capture?"":"?:")+e.map((e=>l(e))).join("|")+")"}
function p(e){return RegExp(e.toString()+"|").exec("").length-1}
const b=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
;function m(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n
;let i=l(e),s="";for(;i.length>0;){const e=b.exec(i);if(!e){s+=i;break}
s+=i.substring(0,e.index),
i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?s+="\\"+(Number(e[1])+t):(s+=e[0],
"("===e[0]&&n++)}return s})).map((e=>`(${e})`)).join(t)}
const E="[a-zA-Z]\\w*",x="[a-zA-Z_]\\w*",w="\\b\\d+(\\.\\d+)?",y="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",_="\\b(0b[01]+)",O={
begin:"\\\\[\\s\\S]",relevance:0},v={scope:"string",begin:"'",end:"'",
illegal:"\\n",contains:[O]},k={scope:"string",begin:'"',end:'"',illegal:"\\n",
contains:[O]},N=(e,t,n={})=>{const s=i({scope:"comment",begin:e,end:t,
contains:[]},n);s.contains.push({scope:"doctag",
begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
;const o=f("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
;return s.contains.push({begin:h(/[ ]+/,"(",o,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s
},S=N("//","$"),M=N("/\\*","\\*/"),R=N("#","$");var j=Object.freeze({
__proto__:null,APOS_STRING_MODE:v,BACKSLASH_ESCAPE:O,BINARY_NUMBER_MODE:{
scope:"number",begin:_,relevance:0},BINARY_NUMBER_RE:_,COMMENT:N,
C_BLOCK_COMMENT_MODE:M,C_LINE_COMMENT_MODE:S,C_NUMBER_MODE:{scope:"number",
begin:y,relevance:0},C_NUMBER_RE:y,END_SAME_AS_BEGIN:e=>Object.assign(e,{
"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
t.data._beginMatch!==e[1]&&t.ignoreMatch()}}),HASH_COMMENT_MODE:R,IDENT_RE:E,
MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+x,relevance:0},
NUMBER_MODE:{scope:"number",begin:w,relevance:0},NUMBER_RE:w,
PHRASAL_WORDS_MODE:{
begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
},QUOTE_STRING_MODE:k,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/,
end:/\/[gimuy]*/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,contains:[O]}]},
RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
SHEBANG:(e={})=>{const t=/^#![ ]*\//
;return e.binary&&(e.begin=h(t,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:t,
end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)},
TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_IDENT_RE:x,
UNDERSCORE_TITLE_MODE:{scope:"title",begin:x,relevance:0}});function A(e,t){
"."===e.input[e.index-1]&&t.ignoreMatch()}function I(e,t){
void 0!==e.className&&(e.scope=e.className,delete e.className)}function T(e,t){
t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
e.__beforeBegin=A,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
void 0===e.relevance&&(e.relevance=0))}function L(e,t){
Array.isArray(e.illegal)&&(e.illegal=f(...e.illegal))}function B(e,t){
if(e.match){
if(e.begin||e.end)throw Error("begin & end are not supported with match")
;e.begin=e.match,delete e.match}}function P(e,t){
void 0===e.relevance&&(e.relevance=1)}const D=(e,t)=>{if(!e.beforeMatch)return
;if(e.starts)throw Error("beforeMatch cannot be used with starts")
;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t]
})),e.keywords=n.keywords,e.begin=h(n.beforeMatch,g(n.begin)),e.starts={
relevance:0,contains:[Object.assign(n,{endsParent:!0})]
},e.relevance=0,delete n.beforeMatch
},H=["of","and","for","in","not","or","if","then","parent","list","value"],C="keyword"
;function $(e,t,n=C){const i=Object.create(null)
;return"string"==typeof e?s(n,e.split(" ")):Array.isArray(e)?s(n,e):Object.keys(e).forEach((n=>{
Object.assign(i,$(e[n],t,n))})),i;function s(e,n){
t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
;i[n[0]]=[e,U(n[0],n[1])]}))}}function U(e,t){
return t?Number(t):(e=>H.includes(e.toLowerCase()))(e)?0:1}const z={},W=e=>{
console.error(e)},X=(e,...t)=>{console.log("WARN: "+e,...t)},G=(e,t)=>{
z[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),z[`${e}/${t}`]=!0)
},K=Error();function F(e,t,{key:n}){let i=0;const s=e[n],o={},r={}
;for(let e=1;e<=t.length;e++)r[e+i]=s[e],o[e+i]=!0,i+=p(t[e-1])
;e[n]=r,e[n]._emit=o,e[n]._multi=!0}function Z(e){(e=>{
e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
}),(e=>{if(Array.isArray(e.begin)){
if(e.skip||e.excludeBegin||e.returnBegin)throw W("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
K
;if("object"!=typeof e.beginScope||null===e.beginScope)throw W("beginScope must be object"),
K;F(e,e.begin,{key:"beginScope"}),e.begin=m(e.begin,{joinWith:""})}})(e),(e=>{
if(Array.isArray(e.end)){
if(e.skip||e.excludeEnd||e.returnEnd)throw W("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
K
;if("object"!=typeof e.endScope||null===e.endScope)throw W("endScope must be object"),
K;F(e,e.end,{key:"endScope"}),e.end=m(e.end,{joinWith:""})}})(e)}function V(e){
function t(t,n){
return RegExp(l(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":""))
}class n{constructor(){
this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
addRule(e,t){
t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(m(e,{joinWith:"|"
}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
;const t=this.matcherRe.exec(e);if(!t)return null
;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
;return t.splice(0,n),Object.assign(t,i)}}class s{constructor(){
this.rules=[],this.multiRegexes=[],
this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n
;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){
const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex
;let n=t.exec(e)
;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{
const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)}
return n&&(this.regexIndex+=n.position+1,
this.regexIndex===this.count&&this.considerAll()),n}}
if(e.compilerExtensions||(e.compilerExtensions=[]),
e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language.  See documentation.")
;return e.classNameAliases=i(e.classNameAliases||{}),function n(o,r){const a=o
;if(o.isCompiled)return a
;[I,B,Z,D].forEach((e=>e(o,r))),e.compilerExtensions.forEach((e=>e(o,r))),
o.__beforeBegin=null,[T,L,P].forEach((e=>e(o,r))),o.isCompiled=!0;let c=null
;return"object"==typeof o.keywords&&o.keywords.$pattern&&(o.keywords=Object.assign({},o.keywords),
c=o.keywords.$pattern,
delete o.keywords.$pattern),c=c||/\w+/,o.keywords&&(o.keywords=$(o.keywords,e.case_insensitive)),
a.keywordPatternRe=t(c,!0),
r&&(o.begin||(o.begin=/\B|\b/),a.beginRe=t(a.begin),o.end||o.endsWithParent||(o.end=/\B|\b/),
o.end&&(a.endRe=t(a.end)),
a.terminatorEnd=l(a.end)||"",o.endsWithParent&&r.terminatorEnd&&(a.terminatorEnd+=(o.end?"|":"")+r.terminatorEnd)),
o.illegal&&(a.illegalRe=t(o.illegal)),
o.contains||(o.contains=[]),o.contains=[].concat(...o.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>i(e,{
variants:null},t)))),e.cachedVariants?e.cachedVariants:q(e)?i(e,{
starts:e.starts?i(e.starts):null
}):Object.isFrozen(e)?i(e):e))("self"===e?o:e)))),o.contains.forEach((e=>{n(e,a)
})),o.starts&&n(o.starts,r),a.matcher=(e=>{const t=new s
;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function q(e){
return!!e&&(e.endsWithParent||q(e.starts))}class J extends Error{
constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}}
const Y=n,Q=i,ee=Symbol("nomatch"),te=n=>{
const i=Object.create(null),s=Object.create(null),o=[];let r=!0
;const a="Could not find the language '{}', did you forget to load/include a language module?",l={
disableAutodetect:!0,name:"Plain text",contains:[]};let p={
ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
cssSelector:"pre code",languages:null,__emitter:c};function b(e){
return p.noHighlightRe.test(e)}function m(e,t,n){let i="",s=""
;"object"==typeof t?(i=e,
n=t.ignoreIllegals,s=t.language):(G("10.7.0","highlight(lang, code, ...args) has been deprecated."),
G("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
s=e,i=t),void 0===n&&(n=!0);const o={code:i,language:s};N("before:highlight",o)
;const r=o.result?o.result:E(o.language,o.code,n)
;return r.code=o.code,N("after:highlight",r),r}function E(e,n,s,o){
const c=Object.create(null);function l(){if(!N.keywords)return void M.addText(R)
;let e=0;N.keywordPatternRe.lastIndex=0;let t=N.keywordPatternRe.exec(R),n=""
;for(;t;){n+=R.substring(e,t.index)
;const s=_.case_insensitive?t[0].toLowerCase():t[0],o=(i=s,N.keywords[i]);if(o){
const[e,i]=o
;if(M.addText(n),n="",c[s]=(c[s]||0)+1,c[s]<=7&&(j+=i),e.startsWith("_"))n+=t[0];else{
const n=_.classNameAliases[e]||e;u(t[0],n)}}else n+=t[0]
;e=N.keywordPatternRe.lastIndex,t=N.keywordPatternRe.exec(R)}var i
;n+=R.substring(e),M.addText(n)}function g(){null!=N.subLanguage?(()=>{
if(""===R)return;let e=null;if("string"==typeof N.subLanguage){
if(!i[N.subLanguage])return void M.addText(R)
;e=E(N.subLanguage,R,!0,S[N.subLanguage]),S[N.subLanguage]=e._top
}else e=x(R,N.subLanguage.length?N.subLanguage:null)
;N.relevance>0&&(j+=e.relevance),M.__addSublanguage(e._emitter,e.language)
})():l(),R=""}function u(e,t){
""!==e&&(M.startScope(t),M.addText(e),M.endScope())}function d(e,t){let n=1
;const i=t.length-1;for(;n<=i;){if(!e._emit[n]){n++;continue}
const i=_.classNameAliases[e[n]]||e[n],s=t[n];i?u(s,i):(R=s,l(),R=""),n++}}
function h(e,t){
return e.scope&&"string"==typeof e.scope&&M.openNode(_.classNameAliases[e.scope]||e.scope),
e.beginScope&&(e.beginScope._wrap?(u(R,_.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
R=""):e.beginScope._multi&&(d(e.beginScope,t),R="")),N=Object.create(e,{parent:{
value:N}}),N}function f(e,n,i){let s=((e,t)=>{const n=e&&e.exec(t)
;return n&&0===n.index})(e.endRe,i);if(s){if(e["on:end"]){const i=new t(e)
;e["on:end"](n,i),i.isMatchIgnored&&(s=!1)}if(s){
for(;e.endsParent&&e.parent;)e=e.parent;return e}}
if(e.endsWithParent)return f(e.parent,n,i)}function b(e){
return 0===N.matcher.regexIndex?(R+=e[0],1):(T=!0,0)}function m(e){
const t=e[0],i=n.substring(e.index),s=f(N,e,i);if(!s)return ee;const o=N
;N.endScope&&N.endScope._wrap?(g(),
u(t,N.endScope._wrap)):N.endScope&&N.endScope._multi?(g(),
d(N.endScope,e)):o.skip?R+=t:(o.returnEnd||o.excludeEnd||(R+=t),
g(),o.excludeEnd&&(R=t));do{
N.scope&&M.closeNode(),N.skip||N.subLanguage||(j+=N.relevance),N=N.parent
}while(N!==s.parent);return s.starts&&h(s.starts,e),o.returnEnd?0:t.length}
let w={};function y(i,o){const a=o&&o[0];if(R+=i,null==a)return g(),0
;if("begin"===w.type&&"end"===o.type&&w.index===o.index&&""===a){
if(R+=n.slice(o.index,o.index+1),!r){const t=Error(`0 width match regex (${e})`)
;throw t.languageName=e,t.badRule=w.rule,t}return 1}
if(w=o,"begin"===o.type)return(e=>{
const n=e[0],i=e.rule,s=new t(i),o=[i.__beforeBegin,i["on:begin"]]
;for(const t of o)if(t&&(t(e,s),s.isMatchIgnored))return b(n)
;return i.skip?R+=n:(i.excludeBegin&&(R+=n),
g(),i.returnBegin||i.excludeBegin||(R=n)),h(i,e),i.returnBegin?0:n.length})(o)
;if("illegal"===o.type&&!s){
const e=Error('Illegal lexeme "'+a+'" for mode "'+(N.scope||"<unnamed>")+'"')
;throw e.mode=N,e}if("end"===o.type){const e=m(o);if(e!==ee)return e}
if("illegal"===o.type&&""===a)return 1
;if(I>1e5&&I>3*o.index)throw Error("potential infinite loop, way more iterations than matches")
;return R+=a,a.length}const _=O(e)
;if(!_)throw W(a.replace("{}",e)),Error('Unknown language: "'+e+'"')
;const v=V(_);let k="",N=o||v;const S={},M=new p.__emitter(p);(()=>{const e=[]
;for(let t=N;t!==_;t=t.parent)t.scope&&e.unshift(t.scope)
;e.forEach((e=>M.openNode(e)))})();let R="",j=0,A=0,I=0,T=!1;try{
if(_.__emitTokens)_.__emitTokens(n,M);else{for(N.matcher.considerAll();;){
I++,T?T=!1:N.matcher.considerAll(),N.matcher.lastIndex=A
;const e=N.matcher.exec(n);if(!e)break;const t=y(n.substring(A,e.index),e)
;A=e.index+t}y(n.substring(A))}return M.finalize(),k=M.toHTML(),{language:e,
value:k,relevance:j,illegal:!1,_emitter:M,_top:N}}catch(t){
if(t.message&&t.message.includes("Illegal"))return{language:e,value:Y(n),
illegal:!0,relevance:0,_illegalBy:{message:t.message,index:A,
context:n.slice(A-100,A+100),mode:t.mode,resultSoFar:k},_emitter:M};if(r)return{
language:e,value:Y(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:N}
;throw t}}function x(e,t){t=t||p.languages||Object.keys(i);const n=(e=>{
const t={value:Y(e),illegal:!1,relevance:0,_top:l,_emitter:new p.__emitter(p)}
;return t._emitter.addText(e),t})(e),s=t.filter(O).filter(k).map((t=>E(t,e,!1)))
;s.unshift(n);const o=s.sort(((e,t)=>{
if(e.relevance!==t.relevance)return t.relevance-e.relevance
;if(e.language&&t.language){if(O(e.language).supersetOf===t.language)return 1
;if(O(t.language).supersetOf===e.language)return-1}return 0})),[r,a]=o,c=r
;return c.secondBest=a,c}function w(e){let t=null;const n=(e=>{
let t=e.className+" ";t+=e.parentNode?e.parentNode.className:""
;const n=p.languageDetectRe.exec(t);if(n){const t=O(n[1])
;return t||(X(a.replace("{}",n[1])),
X("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"}
return t.split(/\s+/).find((e=>b(e)||O(e)))})(e);if(b(n))return
;if(N("before:highlightElement",{el:e,language:n
}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e)
;if(e.children.length>0&&(p.ignoreUnescapedHTML,p.throwUnescapedHTML))throw new J("One of your code blocks includes unescaped HTML.",e.innerHTML)
;t=e;const i=t.textContent,o=n?m(i,{language:n,ignoreIllegals:!0}):x(i)
;e.innerHTML=o.value,e.dataset.highlighted="yes",((e,t,n)=>{const i=t&&s[t]||n
;e.classList.add("hljs"),e.classList.add("language-"+i)
})(e,n,o.language),e.result={language:o.language,re:o.relevance,
relevance:o.relevance},o.secondBest&&(e.secondBest={
language:o.secondBest.language,relevance:o.secondBest.relevance
}),N("after:highlightElement",{el:e,result:o,text:i})}let y=!1;function _(){
"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(w):y=!0
}function O(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}
function v(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
s[e.toLowerCase()]=t}))}function k(e){const t=O(e)
;return t&&!t.disableAutodetect}function N(e,t){const n=e;o.forEach((e=>{
e[n]&&e[n](t)}))}
"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
y&&_()}),!1),Object.assign(n,{highlight:m,highlightAuto:x,highlightAll:_,
highlightElement:w,
highlightBlock:e=>(G("10.7.0","highlightBlock will be removed entirely in v12.0"),
G("10.7.0","Please use highlightElement now."),w(e)),configure:e=>{p=Q(p,e)},
initHighlighting:()=>{
_(),G("10.6.0","initHighlighting() deprecated.  Use highlightAll() now.")},
initHighlightingOnLoad:()=>{
_(),G("10.6.0","initHighlightingOnLoad() deprecated.  Use highlightAll() now.")
},registerLanguage:(e,t)=>{let s=null;try{s=t(n)}catch(t){
if(W("Language definition for '{}' could not be registered.".replace("{}",e)),
!r)throw t;W(t),s=l}
s.name||(s.name=e),i[e]=s,s.rawDefinition=t.bind(null,n),s.aliases&&v(s.aliases,{
languageName:e})},unregisterLanguage:e=>{delete i[e]
;for(const t of Object.keys(s))s[t]===e&&delete s[t]},
listLanguages:()=>Object.keys(i),getLanguage:O,registerAliases:v,
autoDetection:k,inherit:Q,addPlugin:e=>{(e=>{
e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
e["before:highlightBlock"](Object.assign({block:t.el},t))
}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),o.push(e)},
removePlugin:e=>{const t=o.indexOf(e);-1!==t&&o.splice(t,1)}}),n.debugMode=()=>{
r=!1},n.safeMode=()=>{r=!0},n.versionString="11.9.0",n.regex={concat:h,
lookahead:g,either:f,optional:d,anyNumberOfTimes:u}
;for(const t in j)"object"==typeof j[t]&&e(j[t]);return Object.assign(n,j),n
},ne=te({});return ne.newInstance=()=>te({}),ne}()
;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);/*! `cpp` grammar compiled for Highlight.js 11.9.0 */
(()=>{var e=(()=>{"use strict";return e=>{const t=e.regex,a=e.COMMENT("//","$",{
contains:[{begin:/\\\n/}]
}),n="decltype\\(auto\\)",r="[a-zA-Z_]\\w*::",i="(?!struct)("+n+"|"+t.optional(r)+"[a-zA-Z_]\\w*"+t.optional("<[^<>]+>")+")",s={
className:"type",begin:"\\b[a-z\\d_]*_t\\b"},c={className:"string",variants:[{
begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={
className:"number",variants:[{
begin:"[+-]?(?:(?:[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?|\\.[0-9](?:'?[0-9])*)(?:[Ee][+-]?[0-9](?:'?[0-9])*)?|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*|0[Xx](?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)[Pp][+-]?[0-9](?:'?[0-9])*)(?:[Ff](?:16|32|64|128)?|(BF|bf)16|[Ll]|)"
},{
begin:"[+-]?\\b(?:0[Bb][01](?:'?[01])*|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*|0(?:'?[0-7])*|[1-9](?:'?[0-9])*)(?:[Uu](?:LL?|ll?)|[Uu][Zz]?|(?:LL?|ll?)[Uu]?|[Zz][Uu]|)"
}],relevance:0},l={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
},contains:[{begin:/\\\n/,relevance:0},e.inherit(c,{className:"string"}),{
className:"string",begin:/<.*?>/},a,e.C_BLOCK_COMMENT_MODE]},u={
className:"title",begin:t.optional(r)+e.IDENT_RE,relevance:0
},d=t.optional(r)+e.IDENT_RE+"\\s*\\(",p={
type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"],
keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"],
literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"],
_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"]
},_={className:"function.dispatch",relevance:0,keywords:{
_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"]
},
begin:t.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,t.lookahead(/(<[^<>]+>|)\s*\(/))
},m=[_,l,s,a,e.C_BLOCK_COMMENT_MODE,o,c],f={variants:[{begin:/=/,end:/;/},{
begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
keywords:p,contains:m.concat([{begin:/\(/,end:/\)/,keywords:p,
contains:m.concat(["self"]),relevance:0}]),relevance:0},g={className:"function",
begin:"("+i+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
keywords:p,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:n,keywords:p,relevance:0},{
begin:d,returnBegin:!0,contains:[u],relevance:0},{begin:/::/,relevance:0},{
begin:/:/,endsWithParent:!0,contains:[c,o]},{relevance:0,match:/,/},{
className:"params",begin:/\(/,end:/\)/,keywords:p,relevance:0,
contains:[a,e.C_BLOCK_COMMENT_MODE,c,o,s,{begin:/\(/,end:/\)/,keywords:p,
relevance:0,contains:["self",a,e.C_BLOCK_COMMENT_MODE,c,o,s]}]
},s,a,e.C_BLOCK_COMMENT_MODE,l]};return{name:"C++",
aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:p,illegal:"</",
classNameAliases:{"function.dispatch":"built_in"},
contains:[].concat(f,g,_,m,[l,{
begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function)\\s*<(?!<)",
end:">",keywords:p,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:p},{
match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],
className:{1:"keyword",3:"title.class"}}])}}})();hljs.registerLanguage("cpp",e)
})();
</script>

<!-- merge-html.js -->
<script>
var mergeHTMLPlugin = (function () {
  'use strict';

  var originalStream;

  /**
   * @param {string} value
   * @returns {string}
   */
  function escapeHTML(value) {
    return value
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#x27;');
  }

  /* plugin itself */

  /** @type {HLJSPlugin} */
  const mergeHTMLPlugin = {
    // preserve the original HTML token stream
    "before:highlightElement": ({ el }) => {
      originalStream = nodeStream(el);
    },
    // merge it afterwards with the highlighted token stream
    "after:highlightElement": ({ el, result, text }) => {
      if (!originalStream.length) return;

      const resultNode = document.createElement('div');
      resultNode.innerHTML = result.value;
      result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
      el.innerHTML = result.value;
    }
  };

  /* Stream merging support functions */

  /**
   * @typedef Event
   * @property {'start'|'stop'} event
   * @property {number} offset
   * @property {Node} node
   */

  /**
   * @param {Node} node
   */
  function tag(node) {
    return node.nodeName.toLowerCase();
  }

  /**
   * @param {Node} node
   */
  function nodeStream(node) {
    /** @type Event[] */
    const result = [];
    (function _nodeStream(node, offset) {
      for (let child = node.firstChild; child; child = child.nextSibling) {
        if (child.nodeType === 3) {
          offset += child.nodeValue.length;
        } else if (child.nodeType === 1) {
          result.push({
            event: 'start',
            offset: offset,
            node: child
          });
          offset = _nodeStream(child, offset);
          // Prevent void elements from having an end tag that would actually
          // double them in the output. There are more void elements in HTML
          // but we list only those realistically expected in code display.
          if (!tag(child).match(/br|hr|img|input/)) {
            result.push({
              event: 'stop',
              offset: offset,
              node: child
            });
          }
        }
      }
      return offset;
    })(node, 0);
    return result;
  }

  /**
   * @param {any} original - the original stream
   * @param {any} highlighted - stream of the highlighted source
   * @param {string} value - the original source itself
   */
  function mergeStreams(original, highlighted, value) {
    let processed = 0;
    let result = '';
    const nodeStack = [];

    function selectStream() {
      if (!original.length || !highlighted.length) {
        return original.length ? original : highlighted;
      }
      if (original[0].offset !== highlighted[0].offset) {
        return (original[0].offset < highlighted[0].offset) ? original : highlighted;
      }

      /*
      To avoid starting the stream just before it should stop the order is
      ensured that original always starts first and closes last:

      if (event1 == 'start' && event2 == 'start')
        return original;
      if (event1 == 'start' && event2 == 'stop')
        return highlighted;
      if (event1 == 'stop' && event2 == 'start')
        return original;
      if (event1 == 'stop' && event2 == 'stop')
        return highlighted;

      ... which is collapsed to:
      */
      return highlighted[0].event === 'start' ? original : highlighted;
    }

    /**
     * @param {Node} node
     */
    function open(node) {
      /** @param {Attr} attr */
      function attributeString(attr) {
        return ' ' + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
      }
      // @ts-ignore
      result += '<' + tag(node) + [].map.call(node.attributes, attributeString).join('') + '>';
    }

    /**
     * @param {Node} node
     */
    function close(node) {
      result += '</' + tag(node) + '>';
    }

    /**
     * @param {Event} event
     */
    function render(event) {
      (event.event === 'start' ? open : close)(event.node);
    }

    while (original.length || highlighted.length) {
      let stream = selectStream();
      result += escapeHTML(value.substring(processed, stream[0].offset));
      processed = stream[0].offset;
      if (stream === original) {
        /*
        On any opening or closing tag of the original markup we first close
        the entire highlighted node stack, then render the original tag along
        with all the following original tags at the same offset and then
        reopen all the tags on the highlighted stack.
        */
        nodeStack.reverse().forEach(close);
        do {
          render(stream.splice(0, 1)[0]);
          stream = selectStream();
        } while (stream === original && stream.length && stream[0].offset === processed);
        nodeStack.reverse().forEach(open);
      } else {
        if (stream[0].event === 'start') {
          nodeStack.push(stream[0].node);
        } else {
          nodeStack.pop();
        }
        render(stream.splice(0, 1)[0]);
      }
    }
    return result + escapeHTML(value.substr(processed));
  }

  return mergeHTMLPlugin;

}());
</script>

<!-- trim-nicely.js -->
<script>
var trimNicely = (function () {
  'use strict';

	// this is code from reveal.js under following license:
	
	// Copyright (C) 2011-2024 Hakim El Hattab, http://hakim.se, and reveal.js contributors
  // 
	// Permission is hereby granted, free of charge, to any person obtaining a copy
	// of this software and associated documentation files (the "Software"), to deal
	// in the Software without restriction, including without limitation the rights
	// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	// copies of the Software, and to permit persons to whom the Software is
	// furnished to do so, subject to the following conditions:
  // 
	// The above copyright notice and this permission notice shall be included in
	// all copies or substantial portions of the Software.
  // 
	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	// THE SOFTWARE.

	// Function to perform a better "data-trim" on code snippets
	// Will slice an indentation amount on each line of the snippet (amount based on the line having the lowest indentation length)
	function betterTrim(snippetEl) {
		// Helper functions
		function trimLeft(val) {
			// Adapted from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Polyfill
			return val.replace(/^[\s\uFEFF\xA0]+/g, '');
		}
		function trimLineBreaks(input) {
			//console.log(input);
			var lines = input.split("\n");

			// Trim line-breaks from the beginning
			for (var i = 0; i < lines.length; i++) {
				if (lines[i].trim() === '') {
					lines.splice(i--, 1);
				} else break;
			}

			// Trim line-breaks from the end
			for (var i = lines.length-1; i >= 0; i--) {
				if (lines[i].trim() === '') {
					lines.splice(i, 1);
				} else break;
			}

			return lines.join("\n");
		}

		// Main function for betterTrim()
		return (function(snippetEl) {
			var content = trimLineBreaks(snippetEl.innerHTML);
			var lines = content.split("\n");
			// Calculate the minimum amount to remove on each line start of the snippet (can be 0)
			var pad = lines.reduce(function(acc, line) {
				if (line.length > 0 && trimLeft(line).length > 0 && acc > line.length - trimLeft(line).length) {
					return line.length - trimLeft(line).length;
				}
				return acc;
			}, Number.POSITIVE_INFINITY);
			// Slice each line with this amount
			return lines.map(function(line, index) {
				return line.slice(pad);
			})
			.join("\n");
		})(snippetEl);
	}
	

  /** @type {HLJSPlugin} */
  const trimNicely = {
    // preserve the original HTML token stream
    "before:highlightElement": ({ el }) => {
			if (!el.hasAttribute("no-data-trim")) {
				el.innerHTML = betterTrim(el);
			}
			
    },
    // merge it afterwards with the highlighted token stream
    "after:highlightElement": ({ el, result, text }) => {
      //if (!originalStream.length) return;
      //
      //const resultNode = document.createElement('div');
      //resultNode.innerHTML = result.value;
      //result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
      //el.innerHTML = result.value;
    }
  };

  /* Stream merging support functions */

  

  return trimNicely;

}());
</script>

	
<!-- Noto Serif (external font) -->
<link href="https://fonts.googleapis.com/css?family=Noto+Serif" rel="stylesheet" blocking="render"></link>
	
<!-- Noto Sans (external font) -->
<link href="https://fonts.googleapis.com/css?family=Noto+Sans" rel="stylesheet" blocking="render"></link>
	
	
<!-- Fira Code (external font) -->
<link href="https://fonts.googleapis.com/css?family=Fira+Code" rel="stylesheet" blocking="render"></link>
	
<!-- eel-hana.css -->
<style>
.wording  {
    font-family: 'Noto Serif';
    hyphens: auto;
    line-height: 1.5;
    font-size: var(--base-font-size-10);
    padding-left: 3em;
}

.wording div {
    background: inherit;
}

.wording div.wrapper {
    max-width: 20cm;
    margin: auto;
}

.wording div.texpara {
    margin-top: 3pt;
    margin-bottom: 3pt;
}

.wording table div.texpara {
    margin-top: 0;
    margin-bottom: 0;
}

.wording table.enumerate div.texpara {
    margin-top: 3pt;
    margin-bottom: 3pt;
}

.wording ul {
    list-style-type: none;
    padding-left: 9mm;
    margin-top: 0;
    margin-bottom: 0;
}

.wording ol {
    margin-top: 0;
    margin-bottom: 0;
}

.wording a {
    text-decoration: none;
}

.wording a.hidden_link {
    text-decoration: none;
    color: inherit;
}

.wording li {
    margin-top: 3pt;
    margin-bottom: 3pt;
}

.wording h1 {
    line-height: 1;
    margin-top: 10pt;
    margin-bottom: 10pt;
}

.wording h2 {
    line-height: 1;
    font-size: var(--base-font-size-14);
    margin-top: 10pt;
    margin-bottom: 10pt;
}

.wording h2::after {
    content: "";
    clear: both;
    display: table;
}

.wording h3 {
    line-height: 1;
    margin-top: 10pt;
    margin-bottom: 10pt;
}

.wording h3::after {
    content: "";
    clear: both;
    display: table;
}

.wording h4 {
    line-height: 1;
    margin-top: 10pt;
    margin-bottom: 10pt;
}

.wording h4::after {
    content: "";
    clear: both;
    display: table;
}

.wording ul > li:before {
    content: "\2014";
    position: absolute;
    margin-left: -1.5em;
}

.wording .shy:before {
    content: "\00ad";
    /* This is U+00AD SOFT HYPHEN, same as &shy, but we put it in :before
    	to stop it from being included when the text is copied to the clipboard
    	with Firefox, which is especially annoying when copying to a terminal,
    	where the hyphen characters will show up. */
}


.wording .abbr_ref {
    float: right;
}

.wording .folded_abbr_ref {
    float: right;
}

.wording .unfolded_abbr_ref {
    display: none;
}

.wording .secnum {
    display: inline-block;
    min-width: 35pt;
}

.wording .annexnum {
    display: block;
}

.wording div.sourceLinkParent {
    float: right;
}

.wording a.sourceLink {
    position: absolute;
    opacity: 0;
    margin-left: 10pt;
}

.wording a.sourceLink:hover {
    opacity: 1;
}

.wording a.itemDeclLink {
    position: absolute;
    font-size: 75%;
    text-align: right;
    width: 5em;
    opacity: 0;
}

.wording a.itemDeclLink:hover {
    opacity: 1;
}

.wording div.marginalizedparent {
    position: relative;
    left: -18mm;
}

.wording a.marginalized {
    width: 15mm;
    position: absolute;
    font-size: var(--base-font-size-7);
    text-align: right;
}

.wording a.enumerated_item_num {
    display: block;
    margin-top: 3pt;
    margin-bottom: 3pt;
    margin-right: 6pt;
}

.wording div.para {
    margin-bottom: 6pt;
    margin-top: 6pt;
    text-align: justify;
    min-height: 1.2em;
}

.wording div.section {
    text-align: justify;
}

.wording div.sentence {
    display: inline;
}

.wording a.index {
    position: relative;
    float: right;
    right: -1em;
    display: none;
}

.wording a.index:before {
    position: absolute;
    content: "⟵";
    background-color: #C9FBC9;
}


.wording .indexitems {
    margin-left: 2em;
    text-indent: -2em;
}

.wording div.itemdescr {
    margin-left: 12mm;
}

.wording .bnf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
    font-style: italic;
    margin-left: 25pt;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
    text-indent: -3em;
    padding-left: 3em;
    line-height: 1.5;
}

.wording div.bnf span.texttt {
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording .rebnf {
    font-family: 'Noto Serif';
    font-style: italic;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
    margin-left: 30pt;
    text-indent: -3em;
    padding-left: 3em;
    line-height: 1.5;
}

.wording .simplebnf {
    font-family: 'Noto Serif';
    font-style: italic;
    font-size: var(--base-font-size-10);
    margin-top: 0.5em;
    margin-bottom: 0.5em;
    margin-left: 30pt;
    line-height: 1.5;
}

.wording span.textnormal {
    font-style: normal;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
    white-space: normal;
}

.wording .bnf span.textnormal {
    font-style: normal;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
    white-space: normal;
}

.wording p {
    margin-top: 4pt;
    margin-bottom: 4pt;
}

.wording span.rlap {
    display: inline-block;
    width: 0px;
    text-indent: 0;
}

.wording span.terminal {
    font-family: 'Noto Sans Mono';
    font-style: normal;
    font-size: var(--base-font-size-9);
    white-space: pre-wrap;
}

.wording span.noncxxterminal {
    font-family: 'Noto Sans Mono';
    font-style: normal;
    font-size: var(--base-font-size-9);
}

.wording span.term {
    font-style: italic;
}

.wording span.tcode {
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording span.textbf {
    font-weight: bold;
}

.wording span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording div.footnote span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-8);
}

.wording .bnf span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording .simplebnf span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording .example span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording span.textsc {
    font-variant: small-caps;
}

.wording span.nontermdef {
    font-style: italic;
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording .rebnf a.nontermdef {
    font-style: italic;
    font-family: 'Noto Serif';
}

.wording span.emph {
    font-style: italic;
}

.wording span.techterm {
    font-style: italic;
}

.wording span.mathit {
    font-style: italic;
}

.wording span.mathsf {
    font-family: 'Noto Sans';
}

.wording span.mathrm {
    font-family: 'Noto Serif';
    font-style: normal;
}

.wording span.textrm {
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
}

.wording span.textsl {
    font-style: italic;
}

.wording span.mathtt {
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording span.mbox {
    font-family: 'Noto Serif';
    font-style: normal;
}

.wording span.ungap {
    display: inline-block;
    width: 2pt;
}

.wording span.texttt {
    font-family: 'Noto Sans Mono';
}

.wording span.textit {
    font-style: italic;
}

.wording div.footnote span.texttt {
    font-family: 'Noto Sans Mono';
}

.wording span.tcode_in_codeblock {
    font-family: 'Noto Sans Mono';
    font-style: normal;
    font-size: var(--base-font-size-9);
}

.wording span.phantom {
    color: white;
}
/* Unfortunately, this way the text is still selectable. Another
	option is display:none, but then we lose the nice layout.
	Todo: find proper solution. */

.wording span.math {
    font-style: normal;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
}

.wording span.mathblock {
    display: block;
    margin-left: auto;
    margin-right: auto;
    margin-top: 1.2em;
    margin-bottom: 1.2em;
    text-align: center;
}

.wording span.mathalpha {
    font-style: italic;
}

.wording span.synopsis {
    font-weight: bold;
    margin-top: 0.5em;
    display: block;
}

.wording span.definition {
    font-weight: bold;
    display: block;
}

.wording .codeblock {
    font-family: 'Noto Sans Mono';
    margin-left: 1.2em;
    line-height: 1.5;
    font-size: var(--base-font-size-9);
    white-space: pre;
    display: block;
    margin-top: 3pt;
    margin-bottom: 3pt;
		overflow-x: visible;
		overflow-y: default;
}

.wording table .codeblock {
    margin-right: 0;
}

.wording .outputblock {
    margin-left: 1.2em;
    line-height: 1.5;
    font-family: 'Noto Sans Mono';
    font-size: var(--base-font-size-9);
}

.wording code {
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording div.itemdecl {
    margin-top: 2ex;
}

.wording code.itemdeclcode {
    white-space: pre;
    font-family: 'Noto Sans Mono';
    font-size: var(--base-font-size-9);
    display: block;
		overflow-x: visible;
		overflow-y: default;
}

.wording .comment {
    color: green;
    font-style: italic;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
}

.wording .footnote .comment {
    color: green;
    font-style: italic;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-8);
}

.wording .example .comment {
    color: green;
    font-style: italic;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-9);
}

.wording .note .comment {
    color: green;
    font-style: italic;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-9);
}

.wording span.keyword {
    color: #00607c;
    font-style: normal;
}

.wording span.parenthesis {
    color: #af1915;
}

.wording span.curlybracket {
    color: #af1915;
}

.wording span.squarebracket {
    color: #af1915;
}

.wording span.literal {
    color: #9F6807;
}

.wording span.literalterminal {
    color: #9F6807;
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording span.operator {
    color: #570057;
}

.wording span.anglebracket {
    color: #570057;
}

.wording span.preprocessordirective {
    color: #6F4E37;
}

.wording span.textsuperscript {
    vertical-align: super;
    font-size: smaller;
    line-height: 0;
}

.wording .footnoteref {
    vertical-align: super;
    font-size: smaller;
    line-height: 0;
}

.wording .footnote {
    font-size: var(--base-font-size-8);
}

.wording .footnote .math {
    font-size: var(--base-font-size-8);
}

.wording .footnotenum {
    display: inline-block;
    text-align: right;
    margin-right: 1mm;
    width: 4ch;
}

.wording .footnoteBacklink {
    display: none;
}

.wording .footnoteSeparator {
    background: black;
    margin-top: 5mm;
    height: 1px;
    width: 6cm;
}

.wording div.minipage {
    display: inline-block;
    margin-right: 3em;
}

.wording div.numberedTable {
    text-align: center;
    margin-left: 1em;
    margin-right: 1em;
    margin-bottom: 12pt;
    margin-top: 8pt;
}

.wording div.figure {
    text-align: center;
    margin-left: 2em;
    margin-right: 2em;
    margin-bottom: 12pt;
    margin-top: 3pt;
}

.wording table {
    border: 1px solid black;
    border-collapse: collapse;
    margin-left: auto;
    margin-right: auto;
    margin-top: 7pt;
    text-align: left;
}

.wording td, .wording th {
    padding-left: 8pt;
    padding-right: 8pt;
    vertical-align: top;
}

.wording td.empty {
    padding: 0px;
    padding-left: 1px;
}

.wording td.left {
    text-align: left;
}

.wording td.hidden {
    padding: 0;
    width: 0;
}

.wording td.right {
    text-align: right;
}

.wording td.center {
    text-align: center;
}

.wording td.justify {
    text-align: justify;
}

.wording td.border {
    border-left: 1px solid black;
}

.wording tr.rowsep, .wording td.cline {
    border-top: 1px solid black;
}

.wording tr.capsep {
    border-top: 3px solid black;
    border-top-style: double;
}

.wording th {
    border-bottom: 1px solid black;
}

.wording span.centry {
    font-weight: bold;
}

.wording div.table {
    display: block;
    margin-left: auto;
    margin-right: auto;
    text-align: center;
    width: 90%;
}

.wording span.indented {
    background: inherit;
    display: block;
    margin-left: 2em;
    margin-bottom: 1em;
    margin-top: 1em;
}

.wording span.uppercase {
    text-transform: uppercase;
}

.wording span.ucode {
    font-variant: small-caps;
    text-transform: uppercase;
    font-size: 90%;
}

.wording span.uname {
    font-variant: small-caps;
    text-transform: uppercase;
    font-size: 90%;
}

.wording table.enumerate {
    border: 0;
    margin: 0;
}

.wording table.enumerate td {
    padding: 0;
}

.wording table.enumerate td:first-child {
    width: 1cm;
    text-align: right;
}

@media (prefers-color-scheme: dark) {
    .wording {
        background-color: #171717;
        color: #d0d0d0;
    }

    .wording span.mjx-mstyle {
        color: #d0d0d0 !important
    }

    .wording a.hidden_link {
        text-decoration: none;
        color: inherit;
    }

    .wording span.phantom {
        color: #171717;
    }

    .wording a.index:before {
        color: #d0d0d0;
        background-color: #4b6353;
    }

    .wording .comment {
        color: #35da00;
    }

    .wording .footnote .comment {
        color: #35da00;
    }

    .wording .example .comment {
        color: #35da00;
    }

    .wording .note .comment {
        color: #35da00;
    }

    .wording span.keyword {
        color: #12cabe;
    }

    .wording span.parenthesis {
        color: #ff1515;
    }

    .wording span.curlybracket {
        color: #ff1515;
    }

    .wording span.squarebracket {
        color: #ff1515;
    }

    .wording span.literal {
        color: #dfa837;
    }

    .wording span.literalterminal {
        color: #dfa837;
    }

    .wording span.operator {
        color: #baa6b9;
    }

    .wording span.anglebracket {
        color: #baa6b9;
    }

    .wording span.preprocessordirective {
        color: #b27c58;
    }

    .wording table {
        border-color: #d0d0d0;
    }

    .wording td.border {
        border-color: #d0d0d0;
    }

    .wording td.border {
        border-left-color: #d0d0d0;
    }

    .wording tr.rowsep, td.cline {
        border-top-color: #d0d0d0;
    }

    .wording tr.capsep {
        border-top-color: #d0d0d0;
    }

    .wording th {
        border-bottom-color: #d0d0d0;
    }

    .wording .footnoteSeparator {
        background-color: #d0d0d0;
    }

    .wording text {
        fill: #d0d0d0;
    }

    .wording path {
        stroke: #d0d0d0;
    }

    .wording polygon {
        stroke: #d0d0d0;
        fill: #d0d0d0;
    }

    .wording ellipse {
        stroke: #d0d0d0;
    }

}

.wording .mjx-chtml {
    display: inline-block;
    line-height: 0;
    text-indent: 0;
    text-align: left;
    text-transform: none;
    font-style: normal;
    font-weight: normal;
    font-size: 100%;
    font-size-adjust: none;
    letter-spacing: normal;
    word-wrap: normal;
    word-spacing: normal;
    white-space: nowrap;
    float: none;
    direction: ltr;
    max-width: none;
    max-height: none;
    min-width: 0;
    min-height: 0;
    border: 0;
    margin: 0;
    padding: 1px 0
}

.wording .MJXc-display {
    display: block;
    background: inherit;
    text-align: center;
    margin: 1em 0;
    padding: 0
}

.wording .mjx-chtml[tabindex]:focus, .wording  :focus .mjx-chtml[tabindex] {
    display: inline-table
}

.wording .mjx-full-width {
    text-align: center;
    display: table-cell !important;
    width: 10000em
}

.wording .mjx-math {
    display: inline-block;
    border-collapse: separate;
    border-spacing: 0
}

.wording .mjx-math * {
    display: inline-block;
    -webkit-box-sizing: content-box !important;
    -moz-box-sizing: content-box !important;
    box-sizing: content-box !important;
    text-align: left
}

.wording .mjx-numerator {
    display: block;
    background: inherit;
    text-align: center
}

.wording .mjx-denominator {
    display: block;
    background: inherit;
    text-align: center
}

.wording .MJXc-stacked {
    height: 0;
    position: relative
}

.wording .MJXc-stacked > * {
    position: absolute
}

.wording .MJXc-bevelled > * {
    display: inline-block
}

.wording .mjx-stack {
    display: inline-block
}

.wording .mjx-op {
    display: block;
    background: inherit
}

.wording .mjx-under {
    display: table-cell
}

.wording .mjx-over {
    display: block;
    background: inherit
}

.wording .mjx-over > * {
    padding-left: 0px !important;
    padding-right: 0px !important
}

.wording .mjx-under > * {
    padding-left: 0px !important;
    padding-right: 0px !important
}

.wording .mjx-stack > .mjx-sup {
    display: block;
    background: inherit
}

.wording .mjx-stack > .mjx-sub {
    display: block;
    background: inherit
}

.wording .mjx-prestack > .mjx-presup {
    display: block;
    background: inherit
}

.wording .mjx-prestack > .mjx-presub {
    display: block;
    background: inherit
}

.wording .mjx-delim-h > .mjx-char {
    display: inline-block
}

.wording .mjx-surd {
    vertical-align: top
}

.wording .mjx-mphantom * {
    visibility: hidden
}

.wording .mjx-merror {
    background-color: #FFFF88;
    color: #CC0000;
    border: 1px solid #CC0000;
    padding: 2px 3px;
    font-style: normal;
    font-size: 90%
}

.wording .mjx-annotation-xml {
    line-height: normal
}

.wording .mjx-menclose > svg {
    fill: none;
    stroke: currentColor
}

.wording .mjx-mtr {
    display: table-row
}

.wording .mjx-mlabeledtr {
    display: table-row
}

.wording .mjx-mtd {
    display: table-cell;
    text-align: center
}

.wording .mjx-label {
    display: table-row
}

.wording .mjx-box {
    display: inline-block
}

.wording .mjx-block {
    display: block;
    background: inherit
}

.wording .mjx-span {
    display: inline
}

.wording .mjx-char {
    display: block;
    background: inherit;
    white-space: pre
}

.wording .mjx-itable {
    display: inline-table;
    width: auto
}

.wording .mjx-row {
    display: table-row
}

.wording .mjx-cell {
    display: table-cell
}

.wording .mjx-table {
    display: table;
    width: 100%
}

.wording .mjx-line {
    display: block;
    background: inherit;
    height: 0
}

.wording .mjx-strut {
    width: 0;
    padding-top: 1em
}

.wording .mjx-vsize {
    width: 0
}

.wording .MJXc-space1 {
    margin-left: .167em
}

.wording .MJXc-space2 {
    margin-left: .222em
}

.wording .MJXc-space3 {
    margin-left: .278em
}

.wording .mjx-ex-box-test {
    position: absolute;
		overflow-x: visible;
		overflow-y: default;
    width: 1px;
    height: 60ex
}

.wording .mjx-line-box-test {
    display: table !important
}

.wording .mjx-line-box-test span {
    display: table-cell !important;
    width: 10000em !important;
    min-width: 0;
    max-width: none;
    padding: 0;
    border: 0;
    margin: 0
}

.wording .MJXc-TeX-unknown-R {
    font-family: monospace;
    font-style: normal;
    font-weight: normal
}

.wording .MJXc-TeX-unknown-I {
    font-family: monospace;
    font-style: italic;
    font-weight: normal
}

.wording .MJXc-TeX-unknown-B {
    font-family: monospace;
    font-style: normal;
    font-weight: bold
}

.wording .MJXc-TeX-unknown-BI {
    font-family: monospace;
    font-style: italic;
    font-weight: bold
}

.wording .MJXc-TeX-ams-R {
    font-family: MJXc-TeX-ams-R, MJXc-TeX-ams-Rw
}

.wording .MJXc-TeX-cal-B {
    font-family: MJXc-TeX-cal-B, MJXc-TeX-cal-Bx, MJXc-TeX-cal-Bw
}

.wording .MJXc-TeX-frak-R {
    font-family: MJXc-TeX-frak-R, MJXc-TeX-frak-Rw
}

.wording .MJXc-TeX-frak-B {
    font-family: MJXc-TeX-frak-B, MJXc-TeX-frak-Bx, MJXc-TeX-frak-Bw
}

.wording .MJXc-TeX-math-BI {
    font-family: MJXc-TeX-math-BI, MJXc-TeX-math-BIx, MJXc-TeX-math-BIw
}

.wording .MJXc-TeX-sans-R {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording .MJXc-TeX-sans-B {
    font-family: MJXc-TeX-sans-B, MJXc-TeX-sans-Bx, MJXc-TeX-sans-Bw
}

.wording .MJXc-TeX-sans-I {
    font-family: MJXc-TeX-sans-I, MJXc-TeX-sans-Ix, MJXc-TeX-sans-Iw
}

.wording .MJXc-TeX-script-R {
    font-family: MJXc-TeX-script-R, MJXc-TeX-script-Rw
}

.wording .MJXc-TeX-type-R {
    font-family: 'Noto Sans Mono';
    font-size: var(--base-font-size-10);
}

.wording .MJXc-TeX-cal-R {
    font-family: MJXc-TeX-cal-R, MJXc-TeX-cal-Rw
}

.wording .MJXc-TeX-main-B {
    font-family: MJXc-TeX-main-B, MJXc-TeX-main-Bx, MJXc-TeX-main-Bw
}

.wording .MJXc-TeX-main-I {
    font-style: italic
}

.wording .MJXc-TeX-main-R {
}

.wording .MJXc-TeX-math-I {
    font-style: italic
}

.wording .MJXc-TeX-size1-R {
    font-family: MJXc-TeX-size1-R, MJXc-TeX-size1-Rw
}

.wording .MJXc-TeX-size2-R {
    font-family: MJXc-TeX-size2-R, MJXc-TeX-size2-Rw
}

.wording .MJXc-TeX-size3-R {
    font-family: MJXc-TeX-size3-R, MJXc-TeX-size3-Rw
}

.wording .MJXc-TeX-size4-R {
    font-family: MJXc-TeX-size4-R, MJXc-TeX-size4-Rw
}

.wording .MJXc-TeX-vec-R {
    font-family: MJXc-TeX-vec-R, MJXc-TeX-vec-Rw
}

.wording .MJXc-TeX-vec-B {
    font-family: MJXc-TeX-vec-B, MJXc-TeX-vec-Bx, MJXc-TeX-vec-Bw
}

@font-face {
    font-family: MJXc-TeX-ams-R;
    src: local('MathJax_AMS'), local('MathJax_AMS-Regular')
}

@font-face {
    font-family: MJXc-TeX-ams-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_AMS-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_AMS-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-cal-B;
    src: local('MathJax_Caligraphic Bold'), local('MathJax_Caligraphic-Bold')
}

@font-face {
    font-family: MJXc-TeX-cal-Bx;
    src: local('MathJax_Caligraphic');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-cal-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Bold.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-frak-R;
    src: local('MathJax_Fraktur'), local('MathJax_Fraktur-Regular')
}

@font-face {
    font-family: MJXc-TeX-frak-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-frak-B;
    src: local('MathJax_Fraktur Bold'), local('MathJax_Fraktur-Bold')
}

@font-face {
    font-family: MJXc-TeX-frak-Bx;
    src: local('MathJax_Fraktur');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-frak-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Bold.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-math-BI;
    src: local('MathJax_Math BoldItalic'), local('MathJax_Math-BoldItalic')
}

@font-face {
    font-family: MJXc-TeX-math-BIx;
    src: local('MathJax_Math');
    font-weight: bold;
    font-style: italic
}

@font-face {
    font-family: MJXc-TeX-math-BIw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Math-BoldItalic.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Math-BoldItalic.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-sans-R;
    src: local('MathJax_SansSerif'), local('MathJax_SansSerif-Regular')
}

@font-face {
    font-family: MJXc-TeX-sans-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-sans-B;
    src: local('MathJax_SansSerif Bold'), local('MathJax_SansSerif-Bold')
}

@font-face {
    font-family: MJXc-TeX-sans-Bx;
    src: local('MathJax_SansSerif');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-sans-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Bold.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-sans-I;
    src: local('MathJax_SansSerif Italic'), local('MathJax_SansSerif-Italic')
}

@font-face {
    font-family: MJXc-TeX-sans-Ix;
    src: local('MathJax_SansSerif');
    font-style: italic
}

@font-face {
    font-family: MJXc-TeX-sans-Iw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Italic.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Italic.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-script-R;
    src: local('MathJax_Script'), local('MathJax_Script-Regular')
}

@font-face {
    font-family: MJXc-TeX-script-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Script-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Script-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-type-R;
    src: local('MathJax_Typewriter'), local('MathJax_Typewriter-Regular')
}

@font-face {
    font-family: MJXc-TeX-type-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Typewriter-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Typewriter-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-cal-R;
    src: local('MathJax_Caligraphic'), local('MathJax_Caligraphic-Regular')
}

@font-face {
    font-family: MJXc-TeX-cal-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-main-B;
    src: local('MathJax_Main Bold'), local('MathJax_Main-Bold')
}

@font-face {
    font-family: MJXc-TeX-main-Bx;
    src: local('MathJax_Main');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-main-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Main-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Main-Bold.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-main-I;
    src: local('MathJax_Main Italic'), local('MathJax_Main-Italic')
}

@font-face {
    font-family: MJXc-TeX-main-Ix;
    src: local('MathJax_Main');
    font-style: italic
}

@font-face {
    font-family: MJXc-TeX-main-Iw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Main-Italic.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Main-Italic.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-main-R;
    src: local('MathJax_Main'), local('MathJax_Main-Regular')
}

@font-face {
    font-family: MJXc-TeX-main-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Main-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Main-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-math-I;
    src: local('MathJax_Math Italic'), local('MathJax_Math-Italic')
}

@font-face {
    font-family: MJXc-TeX-math-Ix;
    src: local('MathJax_Math');
    font-style: italic
}

@font-face {
    font-family: MJXc-TeX-math-Iw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Math-Italic.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Math-Italic.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-size1-R;
    src: local('MathJax_Size1'), local('MathJax_Size1-Regular')
}

@font-face {
    font-family: MJXc-TeX-size1-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Size1-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Size1-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-size2-R;
    src: local('MathJax_Size2'), local('MathJax_Size2-Regular')
}

@font-face {
    font-family: MJXc-TeX-size2-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Size2-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Size2-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-size3-R;
    src: local('MathJax_Size3'), local('MathJax_Size3-Regular')
}

@font-face {
    font-family: MJXc-TeX-size3-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Size3-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Size3-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-size4-R;
    src: local('MathJax_Size4'), local('MathJax_Size4-Regular')
}

@font-face {
    font-family: MJXc-TeX-size4-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Size4-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Size4-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-vec-R;
    src: local('MathJax_Vector'), local('MathJax_Vector-Regular')
}

@font-face {
    font-family: MJXc-TeX-vec-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Vector-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Vector-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Vector-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-vec-B;
    src: local('MathJax_Vector Bold'), local('MathJax_Vector-Bold')
}

@font-face {
    font-family: MJXc-TeX-vec-Bx;
    src: local('MathJax_Vector');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-vec-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Vector-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Vector-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Vector-Bold.otf') format('opentype')
}

.wording div.example {
	display: block;
	margin-top: 5pt;
	margin-bottom: 5pt;
	font-size: var(--base-font-size-11);
}

.wording div.note {
	display: block;
	margin-top: 5pt;
	margin-bottom: 5pt;
	font-size: var(--base-font-size-11);
}

.wording div.example {
	display: block;
	margin-top: 5pt;
	margin-bottom: 5pt;
	font-size: var(--base-font-size-9);
}

.wording div.note {
	display: block;
	margin-top: 5pt;
	margin-bottom: 5pt;
	font-size: var(--base-font-size-9);
}

.wording div.note .texttt { font-size: var(--base-font-size-9); }
.wording div.example .texttt { font-size: var(--base-font-size-9); }

.wording div.note .textsf { font-family: 'Noto Sans'; font-size: var(--base-font-size-9); }
.wording div.example .textsf { font-family: 'Noto Sans'; font-size: var(--base-font-size-9); }

.wording div.note .math { font-size: var(--base-font-size-9); }
.wording div.example .math { font-size: var(--base-font-size-9); }

.wording a.footnotenum { display: none; }
.wording div.footnote { display: none; }
.wording div.footnoteSeparator { display: none; }
.wording .footnoteref { display: none; }

.wording div.nonNormativeOnly { display: none; }


</style>
	
<!-- may.css -->
<style>
:root {
	--hana-nav-size: 300px;
	--hana-article-left-padding: 300px;
	--hana-background: white;
	--hana-foreground: black;
	--hana-accent: hsl(215, 100%, 35%);
	--hana-hsl-saturated-bright: hsl(0 100% 75%);
	--hana-hsl-saturated-bright-contrast: hsl(0 100% 0%);
	--hana-nav-hide-transform: translate(-300px, 0px);
}

@media (prefers-color-scheme: dark) {
	:root {
		--hana-background: #111;
		--hana-foreground: #DDD;
		--hana-accent: hsl(215, 50%, 73%);
		--hana-hsl-saturated-bright: hsl(0 25% 25%);
		--hana-hsl-saturated-bright-contrast: hsl(0 100% 50%);
	}
}

@media print {
	:root {
		--hana-accent: hsl(215, 100%, 23%);
	}
}

@media screen and (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}
}

@media only screen and (width >= 1000px) {
body:has(#hide.enabled) {
	--hana-article-left-padding: 0;
}
}

@media only screen and (width < 1000px) {
	body {
		font-size: 150%;
	}
}

/* derived and named colors */
:root {
	--hana-menu-background: color-mix(in hsl, var(--hana-background), var(--hana-foreground) 3%);
	--hana-title-background: var(--hana-background);
	--hana-accent-foreground: color-mix(in lab, var(--hana-accent), var(--hana-foreground) 50%);
}

:root {
  overscroll-behavior: none;
}

body {
	overscroll-behavior: none;
	background-color: var(--hana-background);
	color: var(--hana-foreground);
	padding: 0;
	margin: 0;
	font-family: "Noto Serif", "CMU Sans Serif", "Times New Roman";
}

body::backdrop {
	background-color: var(--hana-background);
}

code {
	font-family: "Fira Code", "CMU Typewriter Text", "Times New Roman";
	font-size: 90%;
}

#hide {
	position: fixed;
	left: calc(var(--hana-nav-size) - 2em);
	bottom: 0.5em;
	cursor: pointer;
	z-index: 2000;
	transition: left 0.5s, color 0.5s, transform 0.5s ease-in-out;
	color: color-mix(in hsl, var(--hana-foreground), var(--hana-background) 80%);
	font-size: 20px;
}

@media only screen and (width >= 1000px) {
	#hide.enabled {
		left: 1em;
		transform: rotate(-180deg);
	}

	body:has(#hide.enabled) nav {
		transform: var(--hana-nav-hide-transform);
	}
}



nav {
	position: fixed;
	top: 0;
	left: 0;
	bottom: 0;
	width: var(--hana-nav-size);
	padding: 1em;
	background: var(--hana-menu-background);
	color: var(--hana-foreground);
	box-sizing: border-box;
	
	overflow-wrap: break-word;
	hyphens: auto;
	word-spacing: 0;
	font-size: 90%;
	overflow-y: scroll;
	
	h1 {
		margin-top: 0;
		margin-bottom: 0;
	}
	
	.paper-info {
		display: grid;
		grid-template-columns: auto 1fr;
		.key {
			text-align: right;
			font-weight: bold;
			padding-right: 0.5em;
		}
		padding-right: 1em;
	}
	
	#toc {
		display: grid;
		grid-template-columns: 1fr;
		padding-top: 0.5lh;
		padding-bottom: 1lh;
		h1 {
			margin-bottom: 0.5em;
		}
		ul {
			padding-left: 1em;
			list-style-type: square;
		}
		> ul {
			padding-left: 2em;
			margin: 0;
		}
		
	}
}

@media only screen and (width < 1000px) {
	:root {
		--hana-article-left-padding: 0;
		--hana-title-background: var(--hana-menu-background);
	}
	nav {
		position: static;
		width: 100vw;
		margin: 0;
	}
	#hide {
		display: none;
	}
}

@media print {
	:root {
		--hana-article-left-padding: 0;
		--hana-title-background: var(--hana-menu-background);
	}
	nav {
		position: static;
		width: 100vw;
		margin: 0;
		transform: none !important;
	}
	section > p, section > pre {
		break-inside: avoid;
	}
	#toc {
		display: none;
	}
	#hide {
		display: none;
	}
}


article {	
	color: var(--hana-foreground);
	padding: 1em;
	margin-left: var(--hana-article-left-padding);
	max-width: 100vw;
	
	p:has(+section) {
		margin-bottom: 0;
	}
	
	section {
		> *:last-child {
			margin-bottom: 0;
		}
	}
	
	.wording, pre, code {
		background: color-mix(in lab, var(--hana-accent), var(--hana-background) 98%);
		&code {
			color: var(--hana-accent-foreground);
		}
	}
	
	.wording, pre {
		padding: 1em;
		border-radius: 1em;
		> *:first-child {
			margin-top: 0
		}
		> *:last-child {
			margin-bottom: 0
		}
	}
	
	.wording pre {
		padding: 0;
	}
	
	&.transitionable {
		/*transition: margin-left 0.5s;*/
	}
	
	pre {
		tab-size: 2;
		
		text-align: left;
		white-space: pre-wrap;
	  word-break: break-all;
		overflow-x: wrap;
		overflow-wrap: anywhere;
		
		code.hljs {
			.added, .removed, .before, .after {
				line-height: 1.3;
			}
			
			font-variant-ligatures: none;
			line-height: 1.3;
			* {
				font-size-adjust: 0.5;
			}
			.hljs-keyword, .hljs-built_in, .hljs-type {
				font-weight: bold;
			}
			.hljs-string {
				font-style: italic;
				text-decoration: underline;
			}
			.hljs-comment {
				color: color-mix(in hsl, currentcolor, var(--hana-background) 50%);
			}
		}
	}
	
	p:first-child {
		margin-top: 0;
	}
	
	p {
		color: color-mix(in hsl, var(--hana-foreground), var(--hana-background) 15%);
		text-align: left;
		overflow-wrap: break-word;
		hyphens: auto;
		word-spacing: 0;
		text-wrap: pretty;
	}
	
	.before {
		--hana-context-background: hsl(from var(--hana-hsl-saturated-bright) 0 s l);
		--hana-context-accent: hsl(from var(--hana-hsl-saturated-bright-contrast) 0 s l);
		z-index: 10;
		padding: 0 0.5em;
	}
	.after {
		--hana-context-background: hsl(from var(--hana-hsl-saturated-bright) 90 s l);
		--hana-context-accent: hsl(from var(--hana-hsl-saturated-bright-contrast) 90 s l);
		z-index: 20;
		padding: 0 0.5em;
	}
	.removed, .rem {
		--hana-context-background: hsl(from var(--hana-hsl-saturated-bright) 0 s l);
		--hana-context-accent: hsl(from var(--hana-hsl-saturated-bright-contrast) 0 s l);
		--hana-context-decoration: hsl(from var(--hana-hsl-saturated-bright) 0 s 40);
		--hana-context-text-decoration: hsl(from var(--hana-hsl-saturated-bright) 0 s 40 / 0.75);
		text-decoration: line-through;
	}
	.added, .add, .change {
		--hana-context-background: hsl(from var(--hana-hsl-saturated-bright) 90 s l);
		--hana-context-accent: hsl(from var(--hana-hsl-saturated-bright-contrast) 90 s l);
		--hana-context-decoration: hsl(from var(--hana-hsl-saturated-bright) 90 s 40);
		--hana-context-text-decoration: hsl(from var(--hana-hsl-saturated-bright) 90 s 40 / 0.75);
	}
	.removed, .rem, .added, .add {
		&, * {
			text-decoration-thickness: 3px;
			text-decoration-color: var(--hana-context-text-decoration);
		}
	}
	.removed, .rem, .added, .add, .change {
		
	}
	.before, .after, .removed, .rem, .added, .add {
		print-color-adjust:exact;
		border: none;
		margin: 0;
		padding: 1px 0;
		background: var(--hana-context-background);
		h1, h2, h3, h4, h5, .note, .example, pre, code {
			background: inherit;
		}
		&, * {
			color: var(--hana-context-accent) !important;
		}
	}
}

body:fullscreen {
	overflow-y: scroll;
}

body:fullscreen article {
	overflow-y: scroll;
}

.added, .removed, .change {
	print-color-adjust:exact;
	&:has(&.selected-current) {
		z-index: 5006;
		position: relative;
		outline: 2px solid var(--hana-context-decoration);

		&, .added, .removed, change {
			&:not(.selected-current) {
				--hana-local-background: hsl(from var(--hana-context-background) calc(h - 15) calc(s) l);
				background: var(--hana-local-background) !important;
				outline: 1px solid var(--hana-local-background);
			}
		}
	}
}

.selected-current, .wording .texpara:has(.selected-current), .context:has(.selected-current) {
	z-index: 5005;
	position: relative;
	outline: 2px solid var(--hana-context-decoration);
	background: var(--hana-context-background);
	--special-hana: hana;
}

section:has(.selected-current) {
	& > h1 {
		z-index: 5030;
	}
	& > h2 {
		z-index: 5025;
	}
	& > h3 {
		z-index: 5020;
	}
	& > h4 {
		z-index: 5015;
	}
	& > h5 {
		z-index: 5010;
	}
}

#overlay {
	display: block;
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	right: 0;
	z-index: 5000;
	background-color: rgb(from var(--hana-background) r g b / 0.75);
	pointer-events: none;
}

/* links are all defined here! */
a {
	color: var(--hana-accent);
	&:visited {
		color: hsl(from var(--hana-accent) calc(h - 120) s l);
	}
	&:hover {
		color: hsl(from var(--hana-accent) calc(h + 120) s l) !important;
	}
	&::after {
		margin-left: 0.2em;
		display: inline-block;
		font-size: 80%;
		width: 1em;
		height: 1em;
	}
	&:target {
		outline: none;
		&::after {
			content: "⚓︎";
		}
	}
	&[href^="https://"], &[href^="http://"] {
		&:not(&.revision):not([href^="http://eel.is"]):not([href^="https://eel.is"]):not([href^="http://github.com/Eelis/"]) {
			@media only screen {
				&::after {
					font-family: "Noto Serif", "CMU Sans Serif", "Times New Roman";
					font-size: 14px;
					content: "⎋";
					transform: scale(-1, 1);
				}
			}
		}
	}
}

section {
	position: relative;
}

h1, h2, h3, h4, h5, hr {
	word-break: keep-all;
	white-space: nowrap;
	--hana-header-color: color-mix(in hsl, var(--hana-foreground), var(--hana-background) 15%);
	--hana-header-decoration-color: color-mix(in hsl, var(--hana-foreground), var(--hana-background) 75%);
	text-decoration: none;
	margin-bottom: 0;
	margin-top: 0;
	&:not(hr) {
		padding-top: 1lh;
	}
	line-height: 30px;
	a {
		text-decoration: none;
		&, &:visited, &:hover, &:target {
			color: var(--hana-header-color) !important;
		}
	}
}

div:has(>h2) + p {
	margin-top: 0.5em;
}

hr {
	margin-top: 0.8em;
	height: 2px;
  background-color: none;
  border:none;
	border-top: 2px dotted var(--hana-header-decoration-color);
}

article {
	padding-top: 0;
}

h1#name-of-paper {
	/*position: sticky;*/
	top: 0lh;
	left: 16px;
	margin-top: 0;
	z-index: 5950;
	padding-top: 0.5lh;
	padding-bottom: 0.25lh;
}

body {
	position: relative;
}

article {
	position: relative;
	h1, h2, h3, h4, h5 {
		background-color: var(--hana-background);
		/*position: sticky;*/
		top: 0.5lh;
		z-index: 2000;
		box-shadow: 0 10px 10px var(--hana-background);
	}
	.wording {
		h1, h2, h3, h4, h5 {
			--hana-background: transparent;
			background-color: none;
			position: static;
			box-shadow: none;
		}
	}
	h2 {
		top: 1lh;
		z-index: 1900;
		padding-left: 3px;
	}
	h3 {
		top: 2.25lh;
		z-index: 1800;
		padding-left: 6px;
	}
	h4 {
		top: 3.5lh;
		z-index: 1700;
		padding-left: 9px;
	}
	h5 {
		top: 6.5lh;
		z-index: 1800;
		padding-left: 12px;
	}
}

.wording {
	h1, h2, h3, h4, h5 {
		position: static;
	}
}

@media only screen and (width < 1000px) {
	.wording {
		padding-left: 0em !important;
		padding-right: 0em !important;
	}
	body {
		overflow-x: hidden;
	}
	article {
		padding: 0 0.5em;
	}
	p {
		padding: 0 0.5em;
	}
	h1,h2,h3,h4,h5 {
		position: static !important;
		overflow-wrap: anywhere !important;
		word-break: break-word;
		hyphens: auto;
		white-space: pre-wrap;
	}
}


article section > h1, article > h1 {
	border-bottom: 2px solid var(--hana-header-decoration-color);
}

article section > h2 {
	border-bottom: 2px solid var(--hana-header-decoration-color);
}

article section > h3 {
	border-bottom: 2px dotted var(--hana-header-decoration-color);
}

article section > h4, article section > h5 {
	border-bottom: none;
}

.wording {
	padding-left: 2em;
	
	span.codeblock  {
		text-align: left;
		white-space: pre-wrap;
	  word-break: break-all;
		overflow-x: wrap !important;
		overflow-wrap: anywhere;
	}
	
	.comment {
		color: color-mix(in hsl, var(--hana-background), var(--hana-foreground) 75%) !important;
	}
	
	.note, .example {
		background-color: rgba(from var(--hana-foreground) r g b / 3%);
		padding: 0 0.3em;
		margin: 0.3em;
		border-radius: 0.3em;
		font-size: 95% !important;
		*:not(.note):not(.example) {
			background: none;
		}
	}
	
	code {
		text-align: left;
		white-space: pre-wrap;
	  word-break: break-all;
		overflow-x: wrap;
		overflow-wrap: anywhere;
		
		em {
			& * {
				font-style: italic;
				font-weight: normal !important;
			}
		}
	}
}

code, .wording .codeblock, .wording span.texttt, .wording span.terminal, .wording span.noncxxterminal .wording span.tcode, .wording span.mathtt, .wording div.footnote span.texttt, .wording span.tcode_in_codeblock, .wording .outputblock, .wording code.itemdeclcode, .wording span.literalterminal, .wording .MJXc-TeX-type-R {
	font-family: "Fira Code", "Noto Sans Mono", monospace !important;
	font-variant-ligatures: no-contextual;
	line-height: 1.3;
	* {
		font-size-adjust: 0.5;
	}
}

.hana_wording  {
	pre {
		padding-top: 1lh !important;
	}
	h2 {
    line-height: 1 !important;
    font-size: var(--base-font-size-16) !important;
    margin-top: 10pt !important;
    margin-bottom: 10pt !important;
	}
	h3 {
    line-height: 1 !important;
    margin-top: 10pt !important;
    margin-bottom: 10pt !important;
	}
}

@media screen {
	#draft-warning {
		position: fixed;
		bottom: 0;
		right: 0;
		background: red;
		font-family: "Fira Code", "Noto Sans Mono", monospace !important;
		font-size: 150%;
		padding: 8px 100px;
		text-transform: uppercase;
		transform: translateY(-30px) translateX(80px) rotate(-45deg);
		z-index: 50000;
		color: white;
	}
}
@media print {
	#draft-warning {
		display: none;
	}
}

</style>
</head>
<body>

<!-- navigation sidebar -->
	
<nav>
<div class="paper-info">
	<span class="key">Number:</span><span>P3679R0</span>
	<span class="key">Date:</span><span><time>2025-05-16</time></span>
	<span class="key">Audience:</span><span><a href="mailto:Evolution (YOU-NEED-JAVASCRIPT-ENABLED) #RXZvbHV0aW9uIDxleHRAbGlzdHMuaXNvY3BwLm9yZz4/c3ViamVjdD1QMzY3OVIwOiBTRklOQUVhYmxlIGNvbnN0ZXhwciBleGNlcHRpb25z" onclick="return send_email(this)">Evolution</a></span>
	<span class="key">Author:</span><span><a href="mailto:hana dusikova (YOU-NEED-JAVASCRIPT-ENABLED) #SGFuYStEdXMlQzMlQURrb3YlQzMlQTEgPGhhbmlja2FAaGFuaWNrYS5uZXQ+P3N1YmplY3Q9UDM2NzlSMDogU0ZJTkFFYWJsZSBjb25zdGV4cHIgZXhjZXB0aW9ucw==" onclick="return send_email(this)">Hana Dusíková</a><span>
</div>
<hr/>
<div id="toc">
<ul>
<li><a href="#motivation">Motivation</a></li>
<ul>
<li><a href="#sink-example">Sink example</a></li>
<li><a href="#iterator-inside-multiple-layers-of-concepts-example">Iterator inside multiple layers of concepts example</a></li>
</ul>
<li><a href="#design">Design</a></li>
<li><a href="#implementation">Implementation</a></li>
<li><a href="#language-impact">Language impact</a></li>
<li><a href="#proposed-changes-to-wording">Proposed changes to wording</a></li>
<ul>
<li><a href="#feature-test-macro">Feature test macro</a></li>
</ul>
</ul></div>
</nav>
<div id="hide">◀︎</div>
<!-- main content -->
<article spellcheck="true">
	<h1 id="name-of-paper">SFINAEable constexpr exceptions</h1>
<p>The language should interpret a constexpr exception inside a constraint evaluation as making the constraint evaluate to <code>false</code>. Such a failed overload can now cause other overloads to be selected, making those programs well-defined, and allowing constexpr exceptions to be used to fail constraints. If the failed constraint causes the program to not be valid, the exception's error message is a much better error to report than the instantiation path.</p>
<section data-related="motivation"><h2><a href="#motivation" id="motivation">Motivation</a></h2><p>Following example shows how currently (C++26) exceptions thrown during evaluation of constraint check results in an error to compile whole program. And what would be result if constexpr exception would result only in SFINAE.</p>

<pre><code class="language-cpp">
template &lt;typename... Ts&gt; constexpr bool throw_reason(std::format_string&lt;Ts...&gt; f, Ts &amp;&amp;... args) {
    throw exception{std::format(f, std::forward&lt;Ts&gt;(args)...)};
}

template &lt;typename T&gt; concept fits_into_four_bytes = sizeof(T) &lt;= 4 || throw_reason("provided type `{}` is larger than 4 bytes!", display_string_of(^^T));

int overload(special_type value); // special match
int overload(fits_into_four_bytes auto value);

int main() {
	overload(special_type{}); // totally fine
	overload(42);             // also fine
	overload(new int);
	<span class="before">// BEFORE: error: substitution into constraint</span>
	<span class="before">// expression resulted in a non-constant expression</span>
	<span class="after">// AFTER: can't select any overload from candidates:</span>
	<span class="after">// `int overload(special_type value);`</span>
	<span class="after">//    reason: not matching type</span>
	<span class="after">// `int overload(fits_into_four_bytes auto value);`</span>
	<span class="after">//    reason: <span class="hljs-string">provided type `void*` is larger than 4 bytes!</span></span>
}
</code></pre>
<div><a href="https://compiler-explorer.com/z/e47b9Wa3h" target="_blank">Compiler Explorer</a></div>

<section data-related="sink-example"><h3><a href="#sink-example" id="sink-example">Sink example</a></h3><p>Similar example as previous, but with additional overload. Notice how previously throwing in constraint check makes the whole overload set unusable. With this paper, it will compile as one would expect.</p>
<pre><code class="language-cpp">
int overload(special_type value); // special match
int overload(fits_into_four_bytes auto value);
int overload(auto &&); // sink with lowest priority
	
overload(ptr);
<span class="before">// BEFORE: substitution into constraint expression resulted in a non-constant expression</span>
<span class="after">// AFTER: ok, it selected `int overload(auto &&)` "sink" overload</span>
</code></pre>

</section><section data-related="iterator-inside-multiple-layers-of-concepts-example"><h3><a href="#iterator-inside-multiple-layers-of-concepts-example" id="iterator-inside-multiple-layers-of-concepts-example">Iterator inside multiple layers of concepts example</a></h3><pre><code class="language-cpp">
struct hana_super_awesome_container {
	// ...
	hana_iterator begin();
	hana_sentinel end();
};

my_container my_obj{...};

std::ranges::reverse(obj);
<span class="before">// BEFORE: a multiple pages long error messages which</span>
<span class="before">//         will cut the important reason due error depth limit.</span>
<span class="after">// AFTER: simple error: <span class="hljs-string">provided iterator `hana_iterator` is not decrementable</span></span>
</code></pre>
<p>I'm aware some compilers are getting better in error reporting with concepts. Point is if a library author can provide a custom simple explanation why something is not working it will probably be always better than anything compiler can do automatically.</p>

</section></section><section data-related="design"><h2><a href="#design" id="design">Design</a></h2><p>All outermost constraint are evaluated like they are wrapped in <code>try-catch</code> which returns <code>false</code> for any exception thrown from the body of the constraint.</p>

<pre><code class="language-cpp">
template &lt;<i class="custom-black">template-arguments</i>&gt; concept name = [] {
	try { 
		return &lt;EXPR&gt;;
	} catch (...) {
		<em class="custom-black">store-error-message</em>(<em>exception</em>.what());
		return false;
	}
};
</code></pre>


<p>This makes programs valid in presence of alternative overload candidate. This is useful to introduce sink overloads and also provide error messages in case there is no alternative overload candidate as a reason why specific constraint check failed or overload candidate failed.</p>
</section><section data-related="implementation"><h2><a href="#implementation" id="implementation">Implementation</a></h2><p><a href="https://github.com/hanickadot/llvm-project/tree/P3068-constexpr-exceptions">Implemented</a> as an extension for constexpr exception in Clang.</p>
	
</section><section data-related="language-impact"><h2><a href="#language-impact" id="language-impact">Language impact</a></h2><p>Allows previously not allowed evaluation of constraints checks (which lead compilation failure).</p>
	
</section><section data-related="proposed-changes-to-wording"><h2><a href="#proposed-changes-to-wording" id="proposed-changes-to-wording">Proposed changes to wording</a></h2>
<!-- temp.constr.atomic.html (wording) -->
<div class="wording">
<h4 ><a class='secnum' style='min-width:95pt'>13.5.2.3</a> Atomic constraints <a class='abbr_ref'>[temp.constr.atomic]</a></h4><div class='para' id='1'><div class='marginalizedparent'><a class='marginalized' href='#1'>1</a></div><div class='sourceLinkParent'><a class='sourceLink' href='http://github.com/Eelis/draft/tree/3889474f6911bcd3a30f19125ec88bae3a91de9f/source/templates.tex#L1694'>#</a></div><div class='texpara'><div id='1.sentence-1' class='sentence'>An <a class='hidden_link' href='#def:constraint,atomic' title='13.5.2.3&emsp;Atomic constraints&emsp;[temp.constr.atomic]'><span id='def:constraint,atomic'><i >atomic constraint</i></span></a> is formed from
an expression <span class='texttt'>E</span>
and a mapping from the template parameters
that appear within <span class='texttt'>E</span> to
template arguments that are formed via substitution during constraint normalization
in the declaration of a constrained entity (and, therefore, can involve the
unsubstituted template parameters of the constrained entity),
called the <a class='hidden_link' href='#def:parameter_mapping' title='13.5.2.3&emsp;Atomic constraints&emsp;[temp.constr.atomic]'><span id='def:parameter_mapping'><i >parameter mapping</i></span></a> (<a href='temp.constr.decl' title='13.5.3&emsp;Constrained declarations'>[temp.<span class='shy'></span>constr.<span class='shy'></span>decl]</a>)<a class='hidden_link' href='#1.sentence-1'>.</a></div> <div id='note-1' class='note'><div class='texpara'>[<i>Note&nbsp;<a href='#note-1'>1</a></i>:&ensp;<div id='1.sentence-2' class='sentence'>Atomic constraints are formed by <a href='temp.constr.normal#def:constraint,normalization' title='13.5.4&emsp;Constraint normalization&emsp;[temp.constr.normal]'>constraint normalization</a><a class='hidden_link' href='#1.sentence-2'>.</a></div> <div id='1.sentence-3' class='sentence'><span class='texttt'>E</span> is never a <a href='expr.log.and' title='7.6.14&emsp;Logical AND operator&emsp;[expr.log.and]'>logical <span class='textsc'>and</span> expression</a>
nor a <a href='expr.log.or' title='7.6.15&emsp;Logical OR operator&emsp;[expr.log.or]'>logical <span class='textsc'>or</span> expression</a><a class='hidden_link' href='#1.sentence-3'>.</a></div> —&nbsp;<i>end note</i>]</div></div></div></div><div class='para' id='2'><div class='marginalizedparent'><a class='marginalized' href='#2'>2</a></div><div class='sourceLinkParent'><a class='sourceLink' href='http://github.com/Eelis/draft/tree/3889474f6911bcd3a30f19125ec88bae3a91de9f/source/templates.tex#L1709'>#</a></div><div class='texpara'><div id='2.sentence-1' class='sentence'>Two atomic constraints, <span class='math'><span class="mjx-chtml"><span class="mjx-math"><span class="mjx-mrow" aria-hidden="true"><span class="mjx-msubsup"><span class="mjx-base"><span class="mjx-mi"><span class="mjx-char MJXc-TeX-math-I" style="padding-top: 0.225em; padding-bottom: 0.298em;">e</span></span></span><span class="mjx-sub" style="font-size: 70.7%; vertical-align: -0.212em; padding-right: 0.071em;"><span class="mjx-mn"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.372em; padding-bottom: 0.372em;">1</span></span></span></span></span></span></span></span> and <span class='math'><span class="mjx-chtml"><span class="mjx-math"><span class="mjx-mrow" aria-hidden="true"><span class="mjx-msubsup"><span class="mjx-base"><span class="mjx-mi"><span class="mjx-char MJXc-TeX-math-I" style="padding-top: 0.225em; padding-bottom: 0.298em;">e</span></span></span><span class="mjx-sub" style="font-size: 70.7%; vertical-align: -0.212em; padding-right: 0.071em;"><span class="mjx-mn"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.372em; padding-bottom: 0.372em;">2</span></span></span></span></span></span></span></span>, are
<a class='hidden_link' href='#def:atomic_constraint,identical' title='13.5.2.3&emsp;Atomic constraints&emsp;[temp.constr.atomic]'><span id='def:atomic_constraint,identical'><i >identical</i></span></a>
if they are formed from the same appearance of the same
<a href='expr.comma#nt:expression' title='7.6.20&emsp;Comma operator&emsp;[expr.comma]'><span id='ntref:expression'><span class='textsf'><i >expression</i></span></span></a>
and if, given a hypothetical template <span class='math'><span class='mathalpha'>A</span></span>
whose <a href='temp.pre#nt:template-parameter-list' title='13.1&emsp;Preamble&emsp;[temp.pre]'><span id='ntref:template-parameter-list'><span class='textsf'><i >template-parameter-list</i></span></span></a> consists of
<a href='temp.param#nt:template-parameter' title='13.2&emsp;Template parameters&emsp;[temp.param]'><span id='ntref:template-parameter'><span class='textsf'><i >template-parameter</i></span></span></a><i >s</i> corresponding and equivalent (<a href='temp.over.link' title='13.7.7.2&emsp;Function template overloading'>[temp.<span class='shy'></span>over.<span class='shy'></span>link]</a>) to
those mapped by the parameter mappings of the expression,
a <a href='temp.names#nt:template-id' title='13.3&emsp;Names of template specializations&emsp;[temp.names]'><span id='ntref:template-id'><span class='textsf'><i >template-id</i></span></span></a> naming <span class='math'><span class='mathalpha'>A</span></span>
whose <a href='temp.names#nt:template-argument' title='13.3&emsp;Names of template specializations&emsp;[temp.names]'><span id='ntref:template-argument'><span class='textsf'><i >template-argument</i></span></span></a><i >s</i> are
the targets of the parameter mapping of <span class='math'><span class="mjx-chtml"><span class="mjx-math"><span class="mjx-mrow" aria-hidden="true"><span class="mjx-msubsup"><span class="mjx-base"><span class="mjx-mi"><span class="mjx-char MJXc-TeX-math-I" style="padding-top: 0.225em; padding-bottom: 0.298em;">e</span></span></span><span class="mjx-sub" style="font-size: 70.7%; vertical-align: -0.212em; padding-right: 0.071em;"><span class="mjx-mn"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.372em; padding-bottom: 0.372em;">1</span></span></span></span></span></span></span></span>
is the same (<a href='temp.type' title='13.6&emsp;Type equivalence'>[temp.<span class='shy'></span>type]</a>) as
a <a href='temp.names#nt:template-id' title='13.3&emsp;Names of template specializations&emsp;[temp.names]'><span id='ntref:template-id_'><span class='textsf'><i >template-id</i></span></span></a> naming <span class='math'><span class='mathalpha'>A</span></span>
whose <a href='temp.names#nt:template-argument' title='13.3&emsp;Names of template specializations&emsp;[temp.names]'><span id='ntref:template-argument_'><span class='textsf'><i >template-argument</i></span></span></a><i >s</i> are
the targets of the parameter mapping of <span class='math'><span class="mjx-chtml"><span class="mjx-math"><span class="mjx-mrow" aria-hidden="true"><span class="mjx-msubsup"><span class="mjx-base"><span class="mjx-mi"><span class="mjx-char MJXc-TeX-math-I" style="padding-top: 0.225em; padding-bottom: 0.298em;">e</span></span></span><span class="mjx-sub" style="font-size: 70.7%; vertical-align: -0.212em; padding-right: 0.071em;"><span class="mjx-mn"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.372em; padding-bottom: 0.372em;">2</span></span></span></span></span></span></span></span><a class='hidden_link' href='#2.sentence-1'>.</a></div> <div id='note-2' class='note'><div class='texpara'>[<i>Note&nbsp;<a href='#note-2'>2</a></i>:&ensp;<div id='2.sentence-2' class='sentence'>The comparison of parameter mappings of atomic constraints
operates in a manner similar to that of declaration matching
with alias template substitution (<a href='temp.alias' title='13.7.8&emsp;Alias templates'>[temp.<span class='shy'></span>alias]</a>)<a class='hidden_link' href='#2.sentence-2'>.</a></div> <div id='example-1' class='example'><div class='texpara'>[<i>Example&nbsp;<a href='#example-1'>1</a></i>:&ensp;<span class='codeblock'><span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> N<span class='anglebracket'>&gt;</span> <span class='keyword'>constexpr</span> <span class='keyword'>bool</span> Atomic <span class='operator'>=</span> <span class='literal'>true</span>;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> N<span class='anglebracket'>&gt;</span> <span class='keyword'>concept</span> C <span class='operator'>=</span> Atomic<span class='anglebracket'>&lt;</span>N<span class='anglebracket'>&gt;</span>;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> N<span class='anglebracket'>&gt;</span> <span class='keyword'>concept</span> Add1 <span class='operator'>=</span> C<span class='anglebracket'>&lt;</span>N <span class='operator'>+</span> <span class='literal'>1</span><span class='anglebracket'>&gt;</span>;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> N<span class='anglebracket'>&gt;</span> <span class='keyword'>concept</span> AddOne <span class='operator'>=</span> C<span class='anglebracket'>&lt;</span>N <span class='operator'>+</span> <span class='literal'>1</span><span class='anglebracket'>&gt;</span>;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> M<span class='anglebracket'>&gt;</span> <span class='keyword'>void</span> f<span class='parenthesis'>(</span><span class='parenthesis'>)</span>
  <span class='keyword'>requires</span> Add1<span class='anglebracket'>&lt;</span><span class='literal'>2</span> <span class='operator'>*</span> M<span class='anglebracket'>&gt;</span>;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> M<span class='anglebracket'>&gt;</span> <span class='keyword'>int</span> f<span class='parenthesis'>(</span><span class='parenthesis'>)</span>
  <span class='keyword'>requires</span> AddOne<span class='anglebracket'>&lt;</span><span class='literal'>2</span> <span class='operator'>*</span> M<span class='anglebracket'>&gt;</span> <span class='operator'>&amp;</span><span class='operator'>&amp;</span> <span class='literal'>true</span>;

<span class='keyword'>int</span> x <span class='operator'>=</span> f<span class='anglebracket'>&lt;</span><span class='literal'>0</span><span class='anglebracket'>&gt;</span><span class='parenthesis'>(</span><span class='parenthesis'>)</span>;     <span class='comment'>// OK, the atomic constraints from concept <span class='tcode_in_codeblock'>C</span> in both <span class='tcode_in_codeblock'>f</span>s are <span class='tcode_in_codeblock'>Atomic&lt;N&gt;</span></span>
                    <span class='comment'>// with mapping similar to <span class='math'><span class="mjx-chtml"><span class="mjx-math"><span class="mjx-mrow" aria-hidden="true"><span class="mjx-texatom"><span class="mjx-mrow"><span class="mjx-mtext"><span class="mjx-char MJXc-TeX-type-R" style="padding-top: 0.372em; padding-bottom: 0.298em;">N</span></span></span></span><span class="mjx-texatom"><span class="mjx-mrow"></span></span><span class="mjx-mo MJXc-space3"><span class="mjx-char MJXc-TeX-main-R" style="padding-top: 0.225em; padding-bottom: 0.372em;">↦</span></span><span class="mjx-texatom MJXc-space3"><span class="mjx-mrow"></span></span><span class="mjx-texatom"><span class="mjx-mrow"><span class="mjx-mtext"><span class="mjx-char" style="padding-top: 0.446em; padding-bottom: 0.004em;"><span class="mjx-charbox MJXc-TeX-type-R" style="padding-bottom: 0.233em; margin-right: 0.275em;">2 </span><span class="mjx-charbox MJXc-TeX-type-R" style="padding-bottom: 0.233em; margin-right: 0.275em;">* </span><span class="mjx-charbox MJXc-TeX-type-R" style="padding-bottom: 0.233em; margin-right: 0.275em;">M </span><span class="mjx-charbox MJXc-TeX-type-R" style="padding-bottom: 0.233em; margin-right: 0.275em;">+ </span><span class="mjx-charbox MJXc-TeX-type-R" style="padding-bottom: 0.233em;">1</span></span></span></span></span><span class="mjx-texatom"><span class="mjx-mrow"></span></span></span></span></span></span></span>

<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> N<span class='anglebracket'>&gt;</span> <span class='keyword'>struct</span> WrapN;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> N<span class='anglebracket'>&gt;</span> <span class='keyword'>using</span> Add1Ty <span class='operator'>=</span> WrapN<span class='anglebracket'>&lt;</span>N <span class='operator'>+</span> <span class='literal'>1</span><span class='anglebracket'>&gt;</span>;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> N<span class='anglebracket'>&gt;</span> <span class='keyword'>using</span> AddOneTy <span class='operator'>=</span> WrapN<span class='anglebracket'>&lt;</span>N <span class='operator'>+</span> <span class='literal'>1</span><span class='anglebracket'>&gt;</span>;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> M<span class='anglebracket'>&gt;</span> <span class='keyword'>void</span> g<span class='parenthesis'>(</span>Add1Ty<span class='anglebracket'>&lt;</span><span class='literal'>2</span> <span class='operator'>*</span> M<span class='anglebracket'>&gt;</span> <span class='operator'>*</span><span class='parenthesis'>)</span>;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> M<span class='anglebracket'>&gt;</span> <span class='keyword'>void</span> g<span class='parenthesis'>(</span>AddOneTy<span class='anglebracket'>&lt;</span><span class='literal'>2</span> <span class='operator'>*</span> M<span class='anglebracket'>&gt;</span> <span class='operator'>*</span><span class='parenthesis'>)</span>;

<span class='keyword'>void</span> h<span class='parenthesis'>(</span><span class='parenthesis'>)</span> <span class='curlybracket'>{</span>
  g<span class='anglebracket'>&lt;</span><span class='literal'>0</span><span class='anglebracket'>&gt;</span><span class='parenthesis'>(</span><span class='literal'>nullptr</span><span class='parenthesis'>)</span>;    <span class='comment'>// OK, there is only one <span class='tcode_in_codeblock'>g</span></span>
<span class='curlybracket'>}</span>
</span> —&nbsp;<i>end example</i>]</div></div> <div id='2.sentence-3' class='sentence'>
As specified in <a href='temp.over.link' title='13.7.7.2&emsp;Function template overloading'>[temp.<span class='shy'></span>over.<span class='shy'></span>link]</a>,
if the validity or meaning of the program depends on
whether two constructs are equivalent, and
they are functionally equivalent but not equivalent,
the program is ill-formed, no diagnostic required<a class='hidden_link' href='#2.sentence-3'>.</a></div> <div id='example-2' class='example'><div class='texpara'>[<i>Example&nbsp;<a href='#example-2'>2</a></i>:&ensp;<span class='codeblock'><span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> N<span class='anglebracket'>&gt;</span> <span class='keyword'>void</span> f2<span class='parenthesis'>(</span><span class='parenthesis'>)</span>
  <span class='keyword'>requires</span> Add1<span class='anglebracket'>&lt;</span><span class='literal'>2</span> <span class='operator'>*</span> N<span class='anglebracket'>&gt;</span>;
<span class='keyword'>template</span> <span class='anglebracket'>&lt;</span><span class='keyword'>unsigned</span> N<span class='anglebracket'>&gt;</span> <span class='keyword'>int</span> f2<span class='parenthesis'>(</span><span class='parenthesis'>)</span>
  <span class='keyword'>requires</span> Add1<span class='anglebracket'>&lt;</span>N <span class='operator'>*</span> <span class='literal'>2</span><span class='anglebracket'>&gt;</span> <span class='operator'>&amp;</span><span class='operator'>&amp;</span> <span class='literal'>true</span>;
<span class='keyword'>void</span> h2<span class='parenthesis'>(</span><span class='parenthesis'>)</span> <span class='curlybracket'>{</span>
  f2<span class='anglebracket'>&lt;</span><span class='literal'>0</span><span class='anglebracket'>&gt;</span><span class='parenthesis'>(</span><span class='parenthesis'>)</span>;          <span class='comment'>// ill-formed, no diagnostic required:</span>
                    <span class='comment'>// requires determination of subsumption between atomic constraints that are</span>
                    <span class='comment'>// functionally equivalent but not equivalent</span>
<span class='curlybracket'>}</span>
</span> —&nbsp;<i>end example</i>]</div></div> —&nbsp;<i>end note</i>]</div></div></div></div>


<div class='para' id='3'><div class='marginalizedparent'><a class='marginalized' href='#3'>3</a></div><div class='sourceLinkParent'><a class='sourceLink' href='http://github.com/Eelis/draft/tree/3889474f6911bcd3a30f19125ec88bae3a91de9f/source/templates.tex#L1775'>#</a></div><div class='texpara'><div id='3.sentence-1' class='sentence'>To determine if an atomic constraint is
<a class='hidden_link' href='#def:constraint,satisfaction,atomic' title='13.5.2.3&emsp;Atomic constraints&emsp;[temp.constr.atomic]'><span id='def:constraint,satisfaction,atomic'><i >satisfied</i></span></a>,
the parameter mapping and template arguments are
first substituted into its expression<a class='hidden_link' href='#3.sentence-1'>.</a></div> <div id='3.sentence-2' class='sentence'>If substitution results in an invalid type or expression
in the immediate context of the atomic constraint (<a href='temp.deduct.general' title='13.10.3.1&emsp;General'>[temp.<span class='shy'></span>deduct.<span class='shy'></span>general]</a>),
the constraint is not satisfied<a class='hidden_link' href='#3.sentence-2'>.</a></div> <div id='3.sentence-3' class='sentence'>Otherwise, the <a href='conv.lval' title='7.3.2&emsp;Lvalue-to-rvalue conversion&emsp;[conv.lval]'>lvalue-to-rvalue conversion</a>
is performed if necessary,
and <span class='texttt'>E</span> shall be a constant expression of type <span class='texttt'><span class='keyword'>bool</span></span><a class='hidden_link' href='#3.sentence-3'>.</a></div> 

<div id='3.sentence-?' class='sentence added'>If an uncaught exception is thrown during constant evaluation (<a href='thttps://eel.is/c++draft/expr.const#10.22' title='7.7.10.22&emsp;Constant expressions'>[expr.const]</a>) of a constraint then the outermost constraint is evaluated as false.</div>

 <div id='3.sentence-4' class='sentence'>The constraint is satisfied if and only if evaluation of <span class='texttt'>E</span>
results in <span class='texttt'><span class='literal'>true</span></span><a class='hidden_link' href='#3.sentence-4'>.</a></div> 
<div id='3.sentence-5' class='sentence'>If, at different points in the program, the satisfaction result is different
for identical atomic constraints and template arguments,
the program is ill-formed, no diagnostic required<a class='hidden_link' href='#3.sentence-5'>.</a></div> 

<div id='example-3' class='example'><div class='texpara'>[<i>Example&nbsp;<a href='#example-3'>3</a></i>:&ensp;<span class='codeblock'><span class='keyword'>template</span><span class='anglebracket'>&lt;</span><span class='keyword'>typename</span> T<span class='anglebracket'>&gt;</span> <span class='keyword'>concept</span> C <span class='operator'>=</span>
  <span class='keyword'>sizeof</span><span class='parenthesis'>(</span>T<span class='parenthesis'>)</span> <span class='operator'>=</span><span class='operator'>=</span> <span class='literal'>4</span> <span class='operator'>&amp;</span><span class='operator'>&amp;</span> <span class='operator'>!</span><span class='literal'>true</span>;      <span class='comment'>// requires atomic constraints <span class='tcode_in_codeblock'>sizeof(T) == 4</span> and <span class='tcode_in_codeblock'>!true</span></span>

<span class='keyword'>template</span><span class='anglebracket'>&lt;</span><span class='keyword'>typename</span> T<span class='anglebracket'>&gt;</span> <span class='keyword'>struct</span> S <span class='curlybracket'>{</span>
  <span class='keyword'>constexpr</span> <span class='keyword'>operator</span> <span class='keyword'>bool</span><span class='parenthesis'>(</span><span class='parenthesis'>)</span> <span class='keyword'>const</span> <span class='curlybracket'>{</span> <span class='keyword'>return</span> <span class='literal'>true</span>; <span class='curlybracket'>}</span>
<span class='curlybracket'>}</span>;

<span class='keyword'>template</span><span class='anglebracket'>&lt;</span><span class='keyword'>typename</span> T<span class='anglebracket'>&gt;</span> <span class='keyword'>requires</span> <span class='parenthesis'>(</span>S<span class='anglebracket'>&lt;</span>T<span class='anglebracket'>&gt;</span><span class='curlybracket'>{</span><span class='curlybracket'>}</span><span class='parenthesis'>)</span>
<span class='keyword'>void</span> f<span class='parenthesis'>(</span>T<span class='parenthesis'>)</span>;                      <span class='comment'>// #1</span>
<span class='keyword'>void</span> f<span class='parenthesis'>(</span><span class='keyword'>int</span><span class='parenthesis'>)</span>;                    <span class='comment'>// #2</span>

<span class='keyword'>void</span> g<span class='parenthesis'>(</span><span class='parenthesis'>)</span> <span class='curlybracket'>{</span>
  f<span class='parenthesis'>(</span><span class='literal'>0</span><span class='parenthesis'>)</span>;                         <span class='comment'>// error: expression <span class='tcode_in_codeblock'>S&lt;int&gt;{}</span> does not have type <span class='tcode_in_codeblock'>bool</span></span>
<span class='curlybracket'>}</span>                               <span class='comment'>// while checking satisfaction of deduced arguments of #1;</span>
                                <span class='comment'>// call is ill-formed even though #2 is a better match</span>
</span> —&nbsp;<i>end example</i>]</div></div></div></div>





<div class='texpara added'><div id='note-3' class='note'><div class='texpara'>[<i>Note&nbsp;<a href='#note-3'>3</a></i>:&ensp;<div id='3.sentence-2-note' class='sentence'>The compiler can access exception's message via member function <span class="code">what()</span> to print a useful error message to user.</div></div><div id='example-3' class='example'><div class='texpara'>[<i>Example&nbsp;<a href='#example-4'>4</a></i>:&ensp;<span class='codeblock'>consteval bool throw_an_exception() {
  throw std::exception("provided type has different size than a pointer");
} 

template &lt;T&gt; concept same_size_as_pointer = sizeof(T) == sizeof(void*) || throw_an_exception();

static_assert(!same_size_as_pointer&lt;char&gt;); <span class="comment">// OK, char has different size than a pointer</span>

void overload(same_size_as_pointer auto v);

overload('x'); <span class="comment">// Error: "provided type has different size than a pointer"</span>
</span> —&nbsp;<i>end example</i>]</div>—&nbsp;<i>end note</i>]</div></div></div>



</div>

<section data-related="feature-test-macro"><h3><a href="#feature-test-macro" id="feature-test-macro">Feature test macro</a></h3><div class="wording context"><h4><a href="http://eel.is/c++draft/cpp.predefined">15.11 Predefined macro names [cpp.predefined]</a></h4><div class="para"><code>__cpp_constexpr_exceptions <span class="change"><span class="rem">202411L</span><span class="add">202???L</span></span></code></div></div>
</section></section></article>

<script>
	const all_changes = document.querySelectorAll(".wording .added, .wording .removed, .wording .change");
	let position = null;
	
	function set_hash(id) {
		const elem = document.getElementById(id);
		if (elem) {
			elem.id = `${id}-tmp`;
		}
		window.location.hash = id;
		if (elem) {
			elem.id = id;
		}
		return elem;
	}
	
	function disable_highlight_on_previous() {
		if (position != null) {
			//window.location.href.match(/([^#]++)#.++/);
			//window.location.
			set_hash("no-change-selected");
			// hljs is messing with me
			document.getElementById(all_changes[position].id).classList.remove("selected-current");
		}
	}
	
	function scroll_into_view_if_needed(el, scroll_there = true) {
		if (scroll_there) {
			if (!element_is_visible_in_viewport(el)) {
				el.scrollIntoView({behavior: "smooth", block: "center", inline: "center" });
			} else {
				console.log("doesn't need to scroll?!");
			}
		}
		
		return el;
	}
	
	function highlight_index(i = null, scroll_there = true) {
		if (position !== null && i === position) {
			console.log(`disabling overlay: ${i} === ${position}`);
			disable_highlight_on_previous();
			let overlay = document.querySelector("#overlay");
			overlay.remove();
			position = null;
			return;
		}
		
		if (i !== null) {
			disable_highlight_on_previous();
			position = i;
		}
		
		
		let overlay = document.querySelector("#overlay");
		if (!overlay) {
			let overlay = document.createElement("div");
			overlay.id = "overlay";
			document.querySelector("body").appendChild(overlay);
		}
		
		set_hash(`change-${position}`);
		
		
		const current = document.getElementById(all_changes[position].id);
		current.classList.add("selected-current");
		const scroll_anchor = current.querySelector(".scroll-here")
		
		if (scroll_anchor) {
			return scroll_into_view_if_needed(scroll_anchor, scroll_there);
		}
		
		return scroll_into_view_if_needed(current, scroll_there);
	}
	
	function element_is_visible_in_viewport(el) {
	  const { top, left, bottom, right } = el.getBoundingClientRect();
	  const { innerHeight, innerWidth } = window;
		const zoneHeight = innerHeight/5;
		const zoneWidth = innerWidth/5;
		
	  return top >= zoneHeight && bottom <= (innerHeight-zoneHeight);
	};
	
	all_changes.forEach((e, i) => {
		e.style.cursor = "pointer";
		e.id = `change-${i}-real`;
		e.onclick = (ev) => {
			current = highlight_index(i);
			
			ev.alreadyProcessed = true;
		}
	});
	
	document.body.onclick = (ev) => {
		if (position !== null && !ev.alreadyProcessed) {
			highlight_index(position, false);
		}
	};
	
	function next_or_previous_change(step) {
		disable_highlight_on_previous();

		const first = 0;
		const last =  all_changes.length - 1;
		
		if (position === null) {
			if (step < 0) {
				position = last;
			} else if (step > 0) {
				position = first;
			}
		} else {
			position += step;
		}
		
		if (position >= all_changes.length) {
			position = first;
		} else if (position < 0) {
			position = last;
		}
		highlight_index();
	}
	
	
	set_hash(window.location.hash);
	
	window.addEventListener("load", function () {
		const active_change = window.location.hash.match(/change-(?<id>[0-9]+)/);
		if (active_change) {
			const el = highlight_index(Number(active_change[1]), false);
			//console.log("scrolling there!");
			el.scrollIntoView({behavior: "instant", block: "center", inline: "center" });
		}
		window.setTimeout(() => {
			document.querySelector("html").style["scroll-behavior"] = "smooth";
		}, 500);
	});
	
	window.addEventListener("keydown", function (e) {
		if ((e.altKey) && e.code == "ArrowRight") {
			next_or_previous_change(1);
		} else if (position != null && e.code == "ArrowRight") {
			next_or_previous_change(1);
		} else if ((e.altKey) && e.code == "ArrowLeft") {
			next_or_previous_change(-1);
		} else if (position != null && e.code == "ArrowLeft") {
			next_or_previous_change(-1);
		} else if ((e.altKey) && e.code == "KeyF") {
			document.documentElement.requestFullscreen();
		}
	});
	
	const hide_button = document.getElementById("hide");
	hide_button.onclick = (e) => {
		if (hide_button.classList.contains("enabled")) {
			hide_button.classList.remove("enabled");
		} else {
			hide_button.classList.add("enabled");
		}
	};
	
	function navigate(e, elem) {
		//e.preventDefault();
		//return true;
		const target = elem.getAttribute("href");
		history.pushState(null, null, target);
		const target_element = document.getElementById(target.substr(1));
	}
	
	window.setTimeout(() => document.querySelector("article").classList.add("transitionable"), 500);
	
	document.querySelectorAll("a[href^=\"#\"]").forEach((elem) => { elem.onclick = (e) => navigate(e, elem); } );
	
	function send_email(link) {
		const [prefix, encoded] = link.getAttribute("href").split("#",2);
		window.location = "mailto:"+window.atob(encoded);
		return false;
	}
	
	document.querySelectorAll("a").forEach(link => {
		const relative = link.getAttribute("href");
		if (relative && !relative.startsWith("#") && !relative.startsWith("http://") && !relative.startsWith("https://")) {
			link.href= `https://eel.is/c++draft/${relative}`;
		}
		
	})
</script>

<!-- init-hljs.js -->
<script>
// trim must be first, before merge
hljs.addPlugin(trimNicely);
hljs.addPlugin(mergeHTMLPlugin);
hljs.highlightAll();

</script>
</body>
</html>
