<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2021-01-15" />
  <title>We need a language mechanism for customization points</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span. { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

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

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

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

code.sourceCode > span { display: inline; }
</style>
  <style type="text/css">a {
color : #4183C4;
text-decoration: underline;
}
a.marginalized {
text-decoration: none;
}
a.self-link {
text-decoration: none;
}
h1#toctitle {
border-bottom: 1px solid #cccccc;
}
#TOC li {
margin-top: 1px;
margin-bottom: 1px;
}
#TOC ul>li:before { display: none; }
h3.subtitle { margin-top: -15px; }
h1:target { background-color: transparent; }
h2:target { background-color: transparent; }
h3:target { background-color: transparent; }
h4:target { background-color: transparent; }
h5:target { background-color: transparent; }
h6:target { background-color: transparent; }
code span.co { font-family: monospace; }
table tr {
background-color: white;
}
table tr:nth-child(2n) {
background-color: #f6f8fa;
}
#title-block-header > table tr:nth-child(2n) {
background-color: white;
}
td > div.sourceCode {
background-color: inherit;
}
table {
border-collapse: collapse;
}
table td, table th {
border: 1px solid #cccccc;
}
table th {
border-bottom: 1px solid black;
text-align: center;
}
table tr:first-child th {
border-top: 0;
}
table tr:last-child td {
border-bottom: 0;
}
table tr td:first-child,
table tr th:first-child {
border-left: 0;
}
table tr td:last-child,
table tr th:last-child {
border-right: 0;
}
table tbody tr:first-child td {
border-top: 1px solid black;
}
#title-block-header td { border: 0; }
@media all {
body {
margin: 2em;
}
}
@media screen and (min-width: 480px) {
body {
margin: 5em;
}
}
#refs code{padding-left: 0px; text-indent: 0px;}
:root {
--diff-ins: #e6ffed;
--diff-strongins: #acf2bd;
--diff-del: #ffdddd;
--diff-strongdel: #ff8888;
}
span.diffins {
background-color: var(--diff-strongins);
}
span.diffdel {
background-color: var(--diff-strongdel);
}
div.rm { text-decoration: line-through; }
div.rm code.sourceCode { text-decoration: line-through; }
div.addu, span.addu {
color: #006e28;
background-color: var(--diff-ins);
}

div.rm pre, div.add pre { background-color: #f6f8fa; }
div.addu pre { background-color: var(--diff-ins); }
div.add, div.add pre { background-color: var(--diff-ins); }
div.addu blockquote {
border-left: 4px solid #00a000;
padding: 0 15px;
color: #006e28;
text-decoration: none;
}
div.addu blockquote code.sourceCode { text-decoration: none; }
div.addu blockquote pre { text-decoration: none; }
div.addu blockquote pre code { text-decoration: none; }
div.quote {
border-left: 7px solid #ccc;
background: #f9f9f9;
margin: 1.5em 10px;
padding-left: 20px;
}
code.diff span.va { color: #000000; background-color: var(--diff-ins); }
code.diff span.st { color: #000000; background-color: var(--diff-del); }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">We need a language mechanism for customization points</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>P2279R0</td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2021-01-15</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      EWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Barry Revzin<br>&lt;<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.com</a>&gt;<br>
    </td>
  </tr>
</table>

</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#introduction"><span class="toc-section-number">1</span> Introduction<span></span></a>
<ul>
<li><a href="#polymorphism-using-virtual-member-functions"><span class="toc-section-number">1.1</span> Polymorphism using <code class="sourceCode cpp"><span class="kw">virtual</span></code> member functions<span></span></a></li>
<li><a href="#parametric-polymorphism"><span class="toc-section-number">1.2</span> Parametric Polymorphism<span></span></a></li>
<li><a href="#named-conformance-vs-structural-conformance"><span class="toc-section-number">1.3</span> Named Conformance vs Structural Conformance<span></span></a></li>
</ul></li>
<li><a href="#existing-static-polymorphism-strategies"><span class="toc-section-number">2</span> Existing Static Polymorphism Strategies<span></span></a>
<ul>
<li><a href="#class-template-specialization"><span class="toc-section-number">2.1</span> Class Template Specialization<span></span></a></li>
<li><a href="#pure-adl-based-customization"><span class="toc-section-number">2.2</span> Pure ADL-based customization<span></span></a></li>
<li><a href="#customization-point-objects"><span class="toc-section-number">2.3</span> Customization Point Objects<span></span></a></li>
<li><a href="#tag_invoke"><span class="toc-section-number">2.4</span> <code class="sourceCode cpp">tag_invoke</code><span></span></a></li>
<li><a href="#better-enough"><span class="toc-section-number">2.5</span> Better Enough?<span></span></a></li>
<li><a href="#the-swap-example"><span class="toc-section-number">2.6</span> The swap example<span></span></a></li>
</ul></li>
<li><a href="#relevant-work"><span class="toc-section-number">3</span> Relevant Work<span></span></a>
<ul>
<li><a href="#customization-point-functions"><span class="toc-section-number">3.1</span> Customization Point Functions<span></span></a></li>
<li><a href="#reflective-metaprogramming"><span class="toc-section-number">3.2</span> Reflective Metaprogramming<span></span></a></li>
<li><a href="#c0x-concepts"><span class="toc-section-number">3.3</span> C++0x Concepts<span></span></a></li>
<li><a href="#the-contenders"><span class="toc-section-number">3.4</span> The contenders<span></span></a></li>
</ul></li>
<li><a href="#bibliography"><span class="toc-section-number">4</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>C++ is a language that lauds itself on the ability to write good, efficient generic code. So it’s a little strange that here we are in C++20 and yet have surprisingly little language support for proper customization.</p>
<p>It’s worth elaborating a bit on what I mean by “proper customization.” There are a few facilities that I think of when I say this (in no particular order):</p>
<ol type="1">
<li>The ability to see clearly, in code, what the interface is that can (or needs to) be customized.</li>
<li>The ability to provide default implementations that can be overridden, not just non-defaulted functions.</li>
<li>The ability to opt in <em>explicitly</em> to the interface.</li>
<li>The inability to <em>incorrectly</em> opt in to the interface (for instance, if the interface has a function that takes an <code class="sourceCode cpp"><span class="dt">int</span></code>, you cannot opt in by accidentally taking an <code class="sourceCode cpp"><span class="dt">unsigned</span> <span class="dt">int</span></code>).</li>
<li>The ability to easily invoke the customized implementation. Alternatively, the inability to accidentally invoke the base implementation.</li>
<li>The ability to easily verify that a type implements an interface.</li>
<li>The ability to present an atomic group of functionality that needs to be customized together (and diagnosed early).</li>
</ol>
<p>This list is neither complete (I will add a few additional important requirements later in the paper) nor do I consider all of these aspects to be equally important, but it’s a good list to introduce this discussion.</p>
<h2 data-number="1.1" id="polymorphism-using-virtual-member-functions"><span class="header-section-number">1.1</span> Polymorphism using <code class="sourceCode cpp"><span class="kw">virtual</span></code> member functions<a href="#polymorphism-using-virtual-member-functions" class="self-link"></a></h2>
<p>C++ has precisely one language feature that meets all of these criteria: <code class="sourceCode cpp"><span class="kw">virtual</span></code> member functions.</p>
<ol type="1">
<li><p>Given an interface, you can clearly see which functions are <code class="sourceCode cpp"><span class="kw">virtual</span></code> (or pure <code class="sourceCode cpp"><span class="kw">virtual</span></code>), with the caveat that in some cases these functions may be inherited ✔️.</p></li>
<li><p>You can have functions that are pure <code class="sourceCode cpp"><span class="kw">virtual</span></code> (which must be overriden) alongside functions which are <code class="sourceCode cpp"><span class="kw">virtual</span></code> but contain default implementations. This distinction is easy to understand and implement ✔️.</p></li>
<li><p>Implementing a <code class="sourceCode cpp"><span class="kw">virtual</span></code> polymorphism-based interface can only be done via inheritance, which is explicit ✔️. Within that, each individual member function override can be marked <code class="sourceCode cpp"><span class="kw">override</span></code>. This is not mandatory, but can be enforced with <code class="sourceCode cpp"><span class="op">-</span>Wsuggest<span class="op">-</span><span class="kw">override</span></code>, which makes overrides even more explicit ✔️ (and avoids accidental overrides).</p></li>
<li><p>If you attempt to override a function incorrectly, it’s a compile error at point of definition ✔️ (as opposed to being an error at point of use or, worse, not an error at all):</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">struct</span> B <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>    <span class="kw">virtual</span> <span class="dt">void</span> f<span class="op">(</span><span class="dt">int</span><span class="op">)</span>;</span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="op">}</span>;</span>
<span id="cb1-4"><a href="#cb1-4"></a></span>
<span id="cb1-5"><a href="#cb1-5"></a><span class="kw">struct</span> D <span class="op">:</span> B <span class="op">{</span></span>
<span id="cb1-6"><a href="#cb1-6"></a>    <span class="dt">void</span> f<span class="op">(</span><span class="dt">unsigned</span> <span class="dt">int</span><span class="op">)</span> <span class="kw">override</span>;  <span class="co">// error here</span></span>
<span id="cb1-7"><a href="#cb1-7"></a><span class="op">}</span>;</span></code></pre></div></li>
<li><p>Given a pointer to the interface, just invoking the function you want will automatically do virtual dispatch per the language rules, which automatically invokes the most derived implementation. This requires no additional work on the part of either the interface author or interface user ✔️.</p></li>
<li><p>Checking if a type <code class="sourceCode cpp">T</code> implements an interace <code class="sourceCode cpp">I</code> is as easy as checking if <code class="sourceCode cpp">derived_from<span class="op">&lt;</span>T, I<span class="op">&gt;</span></code> holds ✔️.</p></li>
<li><p>If there is an interface has two pure <code class="sourceCode cpp"><span class="kw">virtual</span></code> member functions, there cannot be an implementation of that interface that only implements one of them. You must implement both, otherwise you cannot even construct an instance of the implementation type ✔️.</p></li>
</ol>
<p>Of course, virtual member functions have issues. None bigger than the fact that they are intrusive. You simply cannot opt types that you do not own into an abstract interface, with the fundamental types not being able to opt into any abstract interface at all. And even when the intrusiveness isn’t a total non-starter, we have issues with performance overhead and the need for allocation.</p>
<h2 data-number="1.2" id="parametric-polymorphism"><span class="header-section-number">1.2</span> Parametric Polymorphism<a href="#parametric-polymorphism" class="self-link"></a></h2>
<p>There’s another interesting aspect of using virtual functions for polymorphism that’s worth bringing up. Let’s pick one of the more familiar generic interfaces in C++: <code class="sourceCode cpp">Iterator</code>. How would we implement <code class="sourceCode cpp">InputIterator</code> as an abstract base class?</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">struct</span> InputIterator <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2"></a>    <span class="co">// this one is fine</span></span>
<span id="cb2-3"><a href="#cb2-3"></a>    <span class="kw">virtual</span> input_iterator<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">++()</span> <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb2-4"><a href="#cb2-4"></a>    </span>
<span id="cb2-5"><a href="#cb2-5"></a>    <span class="co">// this one is... questionable</span></span>
<span id="cb2-6"><a href="#cb2-6"></a>    <span class="kw">virtual</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span>input_iterator <span class="kw">const</span><span class="op">&amp;)</span> <span class="kw">const</span> <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb2-7"><a href="#cb2-7"></a>    </span>
<span id="cb2-8"><a href="#cb2-8"></a>    <span class="co">// .. but what about this one?</span></span>
<span id="cb2-9"><a href="#cb2-9"></a>    <span class="kw">virtual</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">*()</span> <span class="kw">const</span> <span class="op">-&gt;</span> <span class="op">????</span>;</span>
<span id="cb2-10"><a href="#cb2-10"></a><span class="op">}</span>;</span></code></pre></div>
<p>We basically cannot make this as an interface. One problem is that we really don’t want to make any two input iterators equality comparable to each other, regardless of what they iterate. But the even bigger problem is: what would <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">*</span></code> return here? There is no useful type we can put there that satisfies all input_iterators - we might want to return <code class="sourceCode cpp"><span class="dt">int</span><span class="op">&amp;</span></code> for some iterators, <code class="sourceCode cpp">std<span class="op">::</span>string <span class="kw">const</span><span class="op">&amp;</span></code> for others, <code class="sourceCode cpp"><span class="dt">double</span><span class="op">*</span></code> for others, etc.</p>
<p>What this example demonstrates is that <code class="sourceCode cpp">InputIterator</code> is a parameterized interface. And with virtual functions, the only we can provide those parameters is by adding template parameters. We take our interface and turn it into an interface template:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R,</span>
<span id="cb3-2"><a href="#cb3-2"></a>          <span class="kw">typename</span> V <span class="op">=</span> remove_cvref_t<span class="op">&lt;</span>R<span class="op">&gt;</span>,</span>
<span id="cb3-3"><a href="#cb3-3"></a>          <span class="kw">typename</span> D <span class="op">=</span> <span class="dt">ptrdiff_t</span><span class="op">&gt;</span></span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="kw">struct</span> InputIterator <span class="op">{</span></span>
<span id="cb3-5"><a href="#cb3-5"></a>    <span class="kw">using</span> value_type <span class="op">=</span> V;</span>
<span id="cb3-6"><a href="#cb3-6"></a>    <span class="kw">using</span> reference <span class="op">=</span> R;</span>
<span id="cb3-7"><a href="#cb3-7"></a>    <span class="kw">using</span> difference_type <span class="op">=</span> D;</span>
<span id="cb3-8"><a href="#cb3-8"></a></span>
<span id="cb3-9"><a href="#cb3-9"></a>    <span class="co">// okay now we can do this one</span></span>
<span id="cb3-10"><a href="#cb3-10"></a>    <span class="kw">virtual</span> reference <span class="kw">operator</span><span class="op">*()</span> <span class="kw">const</span> <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb3-11"><a href="#cb3-11"></a><span class="op">}</span>;</span></code></pre></div>
<p>But now we don’t have an <code class="sourceCode cpp">InputIterator</code> interface. Not really, anyway. We have an <code class="sourceCode cpp">InputIterator<span class="op">&lt;</span><span class="dt">int</span><span class="op">&amp;&gt;</span></code> interface and an <code class="sourceCode cpp">InputIterator<span class="op">&lt;</span>std<span class="op">::</span>string <span class="kw">const</span><span class="op">&amp;&gt;</span></code> one. But that’s not quite the idea we want to express. We call these additional parameters the <em>associated types</em> of an implementation.</p>
<p>Let’s extend our list of requirements to include these, and present compliance in table form for easier reading:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp"><span class="kw">virtual</span></code> <br />member functions</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Interface visible in code</td>
<td>✔️</td>
</tr>
<tr class="even">
<td>Providing default implementations</td>
<td>✔️</td>
</tr>
<tr class="odd">
<td>Explicit opt-in</td>
<td>✔️</td>
</tr>
<tr class="even">
<td>Diagnose incorrect opt-in</td>
<td>✔️</td>
</tr>
<tr class="odd">
<td>Easily invoke the customization</td>
<td>✔️</td>
</tr>
<tr class="even">
<td>Verify implementation</td>
<td>✔️</td>
</tr>
<tr class="odd">
<td>Atomic grouping of functionality</td>
<td>✔️</td>
</tr>
<tr class="even">
<td>Non-intrusive</td>
<td>❌</td>
</tr>
<tr class="odd">
<td>Associated Types</td>
<td>❌</td>
</tr>
</tbody>
</table>
<h2 data-number="1.3" id="named-conformance-vs-structural-conformance"><span class="header-section-number">1.3</span> Named Conformance vs Structural Conformance<a href="#named-conformance-vs-structural-conformance" class="self-link"></a></h2>
<p>One criteria in the above list is the ability to explicitly opt-in to interfaces. I actually consider this quite important.</p>
<p>There are two approaches to checking that a type meets an interface: structural conformance (validate that the signatures of an interface are satisfied) and named conformance (validate that the <em>name</em> of the interface is satisfied).</p>
<p>Virtual member function based polymorphism uses named conformance: you have to inherit, by name, of the interface you want to implement. C++ templates on the other hand, largely rely upon structural conformance. C++20 concepts as a language feature can only check structural conformance. However, sometimes structural checks are insufficient. There are already many cases in even just the standard library for <em>just</em> ranges in which the difference between two concepts cannot be expressed in a structural check and is purely semantic:</p>
<ul>
<li><code class="sourceCode cpp">input_iterator</code> vs <code class="sourceCode cpp">forward_iterator</code></li>
<li><code class="sourceCode cpp">range</code> vs <code class="sourceCode cpp">view</code></li>
<li><code class="sourceCode cpp">range</code> vs <code class="sourceCode cpp">borrowed_range</code></li>
<li><code class="sourceCode cpp">assignable</code> vs the checks that <code class="sourceCode cpp">indirectly_writable</code> does (arguably)</li>
</ul>
<p>The way to express named conformance in is to use something like a type trait (what the first three of these do) or stick with a structural check that is just sufficiently weird as to not exist by accident (what the last one of these does).</p>
<p>A different, concrete example might be useful to demonstrate the necessary difference between named conformance and structural conformance. Let’s say we wanted to create a customization point for erasing a given value from a container (as was added in <span class="citation" data-cites="P1209R0">[<a href="#ref-P1209R0" role="doc-biblioref">P1209R0</a>]</span>). We have the following very different interfaces:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="co">// Erases all elements from &#39;container&#39; that compare equal to &#39;value&#39;</span></span>
<span id="cb4-2"><a href="#cb4-2"></a>std<span class="op">::</span>erase<span class="op">(</span>container, value<span class="op">)</span>;</span>
<span id="cb4-3"><a href="#cb4-3"></a></span>
<span id="cb4-4"><a href="#cb4-4"></a><span class="co">// Erase the element in &#39;container&#39; pointed to by &#39;iterator&#39;</span></span>
<span id="cb4-5"><a href="#cb4-5"></a>container<span class="op">.</span>erase<span class="op">(</span>iterator<span class="op">)</span>;</span></code></pre></div>
<p>Sure, for a given container, it’s unlikely that we’d have some argument that <em>both</em> compares equal to its <code class="sourceCode cpp">value_type</code> <em>and also</em> is convertible to its <code class="sourceCode cpp">const_iterator</code>. But what happens <em>when</em> we come across such a case? Would we consider a container as opting into one interface when it’s actually opting into the other? Or neither? Or if a container provides yet a different <code class="sourceCode cpp">erase</code> function that meets neither of these:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="kw">struct</span> MyContainer <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3"></a>    <span class="kw">using</span> iterator <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb5-4"><a href="#cb5-4"></a>    <span class="kw">using</span> const_iterator <span class="op">=</span> <span class="co">/* ... */</span>;</span>
<span id="cb5-5"><a href="#cb5-5"></a>    </span>
<span id="cb5-6"><a href="#cb5-6"></a>    <span class="co">// erase by iterator, usual container interface</span></span>
<span id="cb5-7"><a href="#cb5-7"></a>    iterator erase<span class="op">(</span>iterator<span class="op">)</span>;</span>
<span id="cb5-8"><a href="#cb5-8"></a>    iterator erase<span class="op">(</span>const_iterator<span class="op">)</span>;</span>
<span id="cb5-9"><a href="#cb5-9"></a>    </span>
<span id="cb5-10"><a href="#cb5-10"></a>    <span class="co">// this container has to erase by index a lot, so</span></span>
<span id="cb5-11"><a href="#cb5-11"></a>    <span class="co">// this is a convenient interface to avoid having to</span></span>
<span id="cb5-12"><a href="#cb5-12"></a>    <span class="co">// write c.erase(c.begin() + idx) all the time</span></span>
<span id="cb5-13"><a href="#cb5-13"></a>    iterator erase<span class="op">(</span><span class="dt">ptrdiff_t</span> idx<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-14"><a href="#cb5-14"></a>        <span class="cf">return</span> erase<span class="op">(</span>begin<span class="op">()</span> <span class="op">+</span> idx<span class="op">)</span>;</span>
<span id="cb5-15"><a href="#cb5-15"></a>    <span class="op">}</span></span>
<span id="cb5-16"><a href="#cb5-16"></a><span class="op">}</span>;</span></code></pre></div>
<p>The author here may not have know about <code class="sourceCode cpp">std<span class="op">::</span>erase<span class="op">(</span>container, value<span class="op">)</span></code> and it would certainly be surprising to them (and other users) if <code class="sourceCode cpp">std<span class="op">::</span>erase<span class="op">(</span>container, <span class="dv">42</span><span class="op">)</span></code> on a <code class="sourceCode cpp">MyContainer<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span></code> instead of erasing those objects that have value <code class="sourceCode cpp"><span class="dv">42</span></code> instead erased the object at index <code class="sourceCode cpp"><span class="dv">42</span></code>.</p>
<p>The fact that we already even have this conflict in the standard library means that it’s quite imperative to be vigilant with concept checks (and hopefully also demonstrates why any kind of unified function call syntax doesn’t really help).</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="existing-static-polymorphism-strategies"><span class="header-section-number">2</span> Existing Static Polymorphism Strategies<a href="#existing-static-polymorphism-strategies" class="self-link"></a></h1>
<p>C++ has two strategies for non-intrusive static polymorphism today:</p>
<ol type="1">
<li>Class Template Specialization</li>
<li>Free functions found by argument-dependent lookup (ADL), which can be subdivided further into:
<ol type="a">
<li>“pure” ADL</li>
<li>customization point objects (see <span class="citation" data-cites="N4381">[<a href="#ref-N4381" role="doc-biblioref">N4381</a>]</span>, <span>16.3.3.3.6
 <a href="https://wg21.link/customization.point.object">[customization.point.object]</a></span>)</li>
<li><code class="sourceCode cpp">tag_invoke</code> (see <span class="citation" data-cites="P1895R0">[<a href="#ref-P1895R0" role="doc-biblioref">P1895R0</a>]</span>)</li>
</ol></li>
</ol>
<p>Not only are both of these non-intrusive, but neither have any additional runtime overhead, nor do either typically require allocation. But how well do they actually do at customization?</p>
<p>This paper will go through these four strategies in turn to see how well they apply to my criteria and where they succeed and where they come up wanting.</p>
<h2 data-number="2.1" id="class-template-specialization"><span class="header-section-number">2.1</span> Class Template Specialization<a href="#class-template-specialization" class="self-link"></a></h2>
<p>Class template specialization is less commonly used than ADL-based free functions, but it’s certainly a viable strategy. Of the more prominent recent libraries, <code class="sourceCode cpp">fmt<span class="op">::</span>format</code> (<span class="citation" data-cites="fmtlib">[<a href="#ref-fmtlib" role="doc-biblioref">fmtlib</a>]</span>, now <code class="sourceCode cpp">std<span class="op">::</span>format</code>) is based on the user specializing the class template <code class="sourceCode cpp">formatter</code> for their types. The format library is, without reservation, a great library. So let’s see how well its main customization point demonstrates the facilities I describe as desirable for customization.</p>
<p>First, can we tell from the code what the interface is? If we look at the <a href="https://github.com/fmtlib/fmt/blob/f8640d4050504ea15096c3861925956db40d436a/include/fmt/core.h#L629-L634">definition</a> of the primary class template, we find:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="co">// A formatter for objects of type T.</span></span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="kw">typename</span> Char <span class="op">=</span> <span class="dt">char</span>, <span class="kw">typename</span> Enable <span class="op">=</span> <span class="dt">void</span><span class="op">&gt;</span></span>
<span id="cb6-3"><a href="#cb6-3"></a><span class="kw">struct</span> formatter <span class="op">{</span></span>
<span id="cb6-4"><a href="#cb6-4"></a>  <span class="co">// A deleted default constructor indicates a disabled formatter.</span></span>
<span id="cb6-5"><a href="#cb6-5"></a>  formatter<span class="op">()</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="op">}</span>;</span></code></pre></div>
<p>This tells us nothing at all ❌. You can certainly tell from this definition that is intended to be specialized by <em>somebody</em> (between the <code class="sourceCode cpp">Enable</code> template parameter and the fact that this class template is otherwise completely useless?) but you can’t tell if it’s intended to be specialized by the library author for the library’s types or by the user for the user’s types.</p>
<p>In this case, there is no “default” formatter - so it makes sense that the primary template doesn’t have any functionality. But the downside is, I have no idea what the functionality should be.</p>
<p>Now, yes, I probably have to read the docs anyway to understand the nuance of the library, but it’s still noteworthy that there is zero information in the code. This isn’t indicative of bad code either, the language facility doesn’t actually allow you to provide such.</p>
<p>The only real way to provide this information is with a concept. In this case, that concept could look like this. But the concept for this interface is actually fairly difficult to express (see <span>20.20.5.1
 <a href="https://wg21.link/formatter.requirements">[formatter.requirements]</a></span>).</p>
<p>Second, do we have the ability to provide default implementations that can be overridden? ❌ No, not really.</p>
<p>The <code class="sourceCode cpp">parse</code> function that the <code class="sourceCode cpp">formatter</code> needs to provide could have a meaningful default: allow only <code class="sourceCode cpp"><span class="st">&quot;{}&quot;</span></code> and parse it accordingly. But you can’t actually provide default implementations using class template specialization as a customization mechanism — you have to override <em>the whole thing</em>.</p>
<p>One way to (potentially) improve this is to separate <code class="sourceCode cpp">parse</code> and <code class="sourceCode cpp">format</code>. Maybe instead of a single <code class="sourceCode cpp">formatter</code> customization class, we have a <code class="sourceCode cpp">format_parser</code> for <code class="sourceCode cpp">parse</code> and <code class="sourceCode cpp">formatter</code> for <code class="sourceCode cpp">format</code>. At least, this is an improvement in the very narrow sense that the user could specialize the two separately – or only the latter. But I’m not sure it’s an improvement in the broader sense of the API of the library. It certainly seems much better to have a single customization entry for formatting, and all I’m describing here is a workaround for a language insufficiency. Alternatively, the formatting library could provide a class that you could inherit from that provides this default behavior. This means more work for the library author (providing each piece of default functionality as a separate component for convenient inheritance) and for the library consumer (that would need to explicitly inherit from each one).</p>
<p>Third, do we have the ability to opt in explicitly to the interface? ✔️ Yep! In fact, explicit opt in is the only way to go here. Indeed, one of the reasons some people dislike class template specialization as a mechanism for customization is precisely because to opt-in you have to do so outside of your class.</p>
<p>Fourth, is there any protection against implementing the interface incorrectly? ❌ Nope! There is nothing that stops me from specializing <code class="sourceCode cpp">formatter<span class="op">&lt;</span>MyType<span class="op">&gt;</span></code> to behave like a <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op">&lt;</span>MyType<span class="op">&gt;</span></code>. There is no reason for me to actually do this, but the language supports it anyway. If you do it sufficiently wrong, it just won’t compile. Hopefully, the class author wrote a sufficiently good concept to verify that you implemented your specialization “well enough” so you get an understandable error message.</p>
<p>But worst case, your incorrect specialization coupled with insufficient vigilance and paranoia on the library author’s part might actually compile and just lead to bad behavior. What if your <code class="sourceCode cpp">std<span class="op">::</span>hash</code> specialization accidentally returns <code class="sourceCode cpp"><span class="dt">uint8_t</span></code> instead of <code class="sourceCode cpp"><span class="dt">size_t</span></code>? What if you’re taking extra copies or forcing undesirable conversions? Took by reference instead of reference to const and are mutating? Very difficult to defend against this.</p>
<p>Fifth, can you easily invoke the customized implementation? ✔️ Yep! This isn’t really a problem with class template specialization. In this case, <code class="sourceCode cpp">formatter<span class="op">&lt;</span>T<span class="op">&gt;::</span>format</code> is the right function you want and is straightforward enough to spell. But you need to duplicate the type, which leads to potential problems. Do you get any protection against invoking the wrong implementation? ❌ Nope! You could call <code class="sourceCode cpp">formatter<span class="op">&lt;</span>U<span class="op">&gt;::</span>format</code> just as easily, and if the arguments happen to line up…?</p>
<p>The defense for this kind of error is that the customization point isn’t really user-facing, it’s only intended for internal consumption. In this case, used by <code class="sourceCode cpp">fmt<span class="op">::</span>format</code> / <code class="sourceCode cpp">std<span class="op">::</span>format</code>. This is best practice. But it’s something extra that needs to be provided by the class author. So I’ll give this one a 🤷 maybe.</p>
<p>Sixth, can you easily verify that a type implements an interface? Arguably, ❌ nope! Not directly at all. You can check that a specialization exists, but that doesn’t tell you anything about whether the specialization is correct. Compare this to the virtual function case, where checking if a <code class="sourceCode cpp">T<span class="op">*</span></code> is convertible to a <code class="sourceCode cpp">Base<span class="op">*</span></code> is sufficient for all virtual-function-based polymorphism.</p>
<p>Here, it would be up to the class author to write a <code class="sourceCode cpp"><span class="kw">concept</span></code> that checks that the user did everything right. But this also something extra that needs to be provided by the class author.</p>
<p>Seventh, can we group multiple pieces of functionality atomically into one umbrella, such that failure to provide all of them can be diagnosed early? 🤷 Kind of. <code class="sourceCode cpp">formatter</code> is a good example here: while you cannot <em>only</em> provide a <code class="sourceCode cpp">parse</code> or <em>only</em> provide a <code class="sourceCode cpp">format</code> function (you <em>must</em> provide both), there isn’t anything in the language that enforces this. I can easily provide a specialization that only has one or the other (or neither), and this will only become an error at the point of use. In this sense, this is no different from any other incorrect implementation. But at least a missing customization point is much easier to diagnose than an incorrect one.</p>
<p>Eighth, is class template specialization non-intrusive? ✔️ Absolutely! Not much else to say here.</p>
<p>Ninth, does class template specialization support associated types? 🤷 Kind of. As with the common theme in this section, you <em>can</em> provide associated types in your specialization (indeed, what is <code class="sourceCode cpp">std<span class="op">::</span>iterator_traits</code> if not a static polymorphism mechanism implemented with class template specialization whose entire job is to provide associated types?), there is nothing in the language that can <em>enforce</em> that these types exist. But, verifying the presence of type names (just like verifying the presence of functions) is a lot easier than verifying that a given function is properly implemented. Types are just easier, less to check.</p>
<p>So how’d we do overall? Let’s update the table:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp"><span class="kw">virtual</span></code> <br />member functions</strong>
</div></th>
<th><div style="text-align:center">
<strong>class template<br />specialization</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Interface visible in code</td>
<td>✔️</td>
<td>❌</td>
</tr>
<tr class="even">
<td>Providing default implementations</td>
<td>✔️</td>
<td>❌</td>
</tr>
<tr class="odd">
<td>Explicit opt-in</td>
<td>✔️</td>
<td>✔️</td>
</tr>
<tr class="even">
<td>Diagnose incorrect opt-in</td>
<td>✔️</td>
<td>❌</td>
</tr>
<tr class="odd">
<td>Easily invoke the customization</td>
<td>✔️</td>
<td>🤷</td>
</tr>
<tr class="even">
<td>Verify implementation</td>
<td>✔️</td>
<td>❌</td>
</tr>
<tr class="odd">
<td>Atomic grouping of functionality</td>
<td>✔️</td>
<td>🤷</td>
</tr>
<tr class="even">
<td>Non-intrusive</td>
<td>❌</td>
<td>✔️</td>
</tr>
<tr class="odd">
<td>Associated Types</td>
<td>❌</td>
<td>🤷</td>
</tr>
</tbody>
</table>
<h2 data-number="2.2" id="pure-adl-based-customization"><span class="header-section-number">2.2</span> Pure ADL-based customization<a href="#pure-adl-based-customization" class="self-link"></a></h2>
<p>There has been innovation in this space over the years. We’ve used to have general guidelines about how to ensure the right thing happens. Then Ranges introduced to us Customization Point Objects. And now there is a discussion about a new model <code class="sourceCode cpp">tag_invoke</code>.</p>
<p>Ranges are probably the most familiar example of using ADL for customization points (after, I suppose, <code class="sourceCode cpp"><span class="op">&lt;&lt;</span></code> for iostreams, but as an operator, it’s inherently less interesting). A type is a <em>range</em> if there is a <code class="sourceCode cpp">begin</code> function that returns some type <code class="sourceCode cpp">I</code> that models <code class="sourceCode cpp">input_or_output_iterator</code> and there is an <code class="sourceCode cpp">end</code> function that returns some type <code class="sourceCode cpp">S</code> that models <code class="sourceCode cpp">sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span></code>.</p>
<p>With pure ADL (ADL classic?), we would have code in a header somewhere (any of a dozen standard library headers brings it in) that looks like this:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> C<span class="op">&gt;</span></span>
<span id="cb7-3"><a href="#cb7-3"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> begin<span class="op">(</span>C<span class="op">&amp;</span> c<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span>c<span class="op">.</span>begin<span class="op">())</span> <span class="op">{</span></span>
<span id="cb7-4"><a href="#cb7-4"></a>        <span class="cf">return</span> c<span class="op">.</span>begin<span class="op">()</span>;</span>
<span id="cb7-5"><a href="#cb7-5"></a>    <span class="op">}</span></span>
<span id="cb7-6"><a href="#cb7-6"></a>    </span>
<span id="cb7-7"><a href="#cb7-7"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb7-8"><a href="#cb7-8"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> begin<span class="op">(</span>T<span class="op">(&amp;</span>a<span class="op">)[</span>N<span class="op">])</span> <span class="op">-&gt;</span> T<span class="op">*</span> <span class="op">{</span></span>
<span id="cb7-9"><a href="#cb7-9"></a>        <span class="cf">return</span> a;</span>
<span id="cb7-10"><a href="#cb7-10"></a>    <span class="op">}</span></span>
<span id="cb7-11"><a href="#cb7-11"></a>    </span>
<span id="cb7-12"><a href="#cb7-12"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> C<span class="op">&gt;</span></span>
<span id="cb7-13"><a href="#cb7-13"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> end<span class="op">(</span>C<span class="op">&amp;</span> c<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span>c<span class="op">.</span>end<span class="op">())</span> <span class="op">{</span></span>
<span id="cb7-14"><a href="#cb7-14"></a>        <span class="cf">return</span> c<span class="op">.</span>end<span class="op">()</span>;</span>
<span id="cb7-15"><a href="#cb7-15"></a>    <span class="op">}</span></span>
<span id="cb7-16"><a href="#cb7-16"></a>    </span>
<span id="cb7-17"><a href="#cb7-17"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T, <span class="dt">size_t</span> N<span class="op">&gt;</span></span>
<span id="cb7-18"><a href="#cb7-18"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> end<span class="op">(</span>T<span class="op">(&amp;</span>a<span class="op">)[</span>N<span class="op">])</span> <span class="op">-&gt;</span> T<span class="op">*</span> <span class="op">{</span></span>
<span id="cb7-19"><a href="#cb7-19"></a>        <span class="cf">return</span> a <span class="op">+</span> N;</span>
<span id="cb7-20"><a href="#cb7-20"></a>    <span class="op">}</span>    </span>
<span id="cb7-21"><a href="#cb7-21"></a><span class="op">}</span></span></code></pre></div>
<p>Let’s run through our criteria:</p>
<ol type="1">
<li><p>Can we see what the interface is in code? ❌ Nope! From the user’s perspective, there’s no difference between these function templates and anything else in the standard library.</p></li>
<li><p>Can you provide default implementations of functions? ✔️ Yep! The begin/end example here doesn’t demonstrate this, but a different customization point would. <code class="sourceCode cpp">size<span class="op">(</span>E<span class="op">)</span></code> can be defined as <code class="sourceCode cpp">end<span class="op">(</span>E<span class="op">)</span> <span class="op">-</span> begin<span class="op">(</span>E<span class="op">)</span></code> for all valid containers, while still allowing a user to override it. Similarly, <code class="sourceCode cpp">std<span class="op">::</span>swap</code> has a default implementation that works fine for most types (if potentially less efficient than could be for some). So this part is fine.</p></li>
<li><p>Can we opt in explicitly? ❌ Nope! You certainly have to explicitly provide <code class="sourceCode cpp">begin</code> and <code class="sourceCode cpp">end</code> overloads for your type to be a range, that much is true. But nowhere in your implementation of those functions is there any kind of annotation that you can provide that indicates <em>why</em> you are writing these functions. The opt-in is only implicit. For <code class="sourceCode cpp">begin</code>/<code class="sourceCode cpp">end</code>, sure, everybody knows what Ranges are — but for less universally known interfaces, some kind of indication of what you are doing could only help.</p>
<p>On the other hand, you can certainly provide a function named <code class="sourceCode cpp">begin</code> for a type that has nothing to do with a range - it could be starting some task, or starting a timer, etc - and there’s no way to say that this has nothing to do with ranges.</p></li>
<li><p>Is there protection against incorrect opt-in? ❌ Nope! What’s stopping me from writing a <code class="sourceCode cpp">begin</code> for my type that returns <code class="sourceCode cpp"><span class="dt">void</span></code>? Nothing. From the language’s perspective, it’s just another function (or function template) and those are certainly allowed to return <code class="sourceCode cpp"><span class="dt">void</span></code>.</p></li>
<li><p>Can we easily invoke the customized implementation? ❌ Nope! Writing <code class="sourceCode cpp">begin<span class="op">(</span>E<span class="op">)</span></code> doesn’t work for a lot of containers, <code class="sourceCode cpp">std<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> doesn’t work for others. A more dangerous example is <code class="sourceCode cpp">std<span class="op">::</span>swap<span class="op">(</span>E, F<span class="op">)</span></code>, which probably compiles and works fine for lots of times but is a subtle performance trap if the type provides a customized implementation and that customized implementation is not an overload in namespace <code class="sourceCode cpp">std</code>.</p>
<p>Instead, you have to write <code class="sourceCode cpp"><span class="kw">using</span> std<span class="op">::</span>swap; swap<span class="op">(</span>E, F<span class="op">)</span>;</code> which while “easy” to write as far as code goes (in the sense that it’s a formula that always works), I would not qualify as “easy” to always remember to do given that the wrong one works.</p></li>
<li><p>Can we easily verify the type implements an interface? ❌ I have to say no here. The “interface” doesn’t even have a name in code, how would you check it? This isn’t just me being pedantic - the only way to check this is to write a separate concept from the customization point. And this is kind of the point that I’m making - these are separate.</p></li>
<li><p>Does anything stop me from providing a non-member <code class="sourceCode cpp">begin</code> but not a non-member <code class="sourceCode cpp">end</code>? Nope ❌. This is similar to the class template specialization case: you can see at point of use that one or the other doesn’t exist, but there’s no way to diagnose this earlier.</p></li>
<li><p>Can we opt-in non-intrusively? ✔️ Yep! It’s just as easy as writing a free function. No issues.</p></li>
<li><p>Can we add associated type support? ❌ I would say no. ADL is entirely about functions and not really about types. An associated type of the range concept would be it’s iterator type, which is the type that <code class="sourceCode cpp">begin</code> returns. But it’s not even easy to call that function, much less get its type properly. Would have to lean no here.</p></li>
</ol>
<p>Not a great solution overall:</p>
<table>
<thead>
<tr class="header">
<th></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp"><span class="kw">virtual</span></code> <br />member functions</strong>
</div></th>
<th><div style="text-align:center">
<strong>class template<br />specialization</strong>
</div></th>
<th><div style="text-align:center">
<strong>Pure<br />ADL</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Interface visible in code</td>
<td>✔️</td>
<td>❌</td>
<td>❌</td>
</tr>
<tr class="even">
<td>Providing default implementations</td>
<td>✔️</td>
<td>❌</td>
<td>✔️</td>
</tr>
<tr class="odd">
<td>Explicit opt-in</td>
<td>✔️</td>
<td>✔️</td>
<td>❌</td>
</tr>
<tr class="even">
<td>Diagnose incorrect opt-in</td>
<td>✔️</td>
<td>❌</td>
<td>❌</td>
</tr>
<tr class="odd">
<td>Easily invoke the customization</td>
<td>✔️</td>
<td>🤷</td>
<td>❌</td>
</tr>
<tr class="even">
<td>Verify implementation</td>
<td>✔️</td>
<td>❌</td>
<td>❌</td>
</tr>
<tr class="odd">
<td>Atomic grouping of functionality</td>
<td>✔️</td>
<td>🤷</td>
<td>❌</td>
</tr>
<tr class="even">
<td>Non-intrusive</td>
<td>❌</td>
<td>✔️</td>
<td>✔️</td>
</tr>
<tr class="odd">
<td>Associated Types</td>
<td>❌</td>
<td>🤷</td>
<td>❌</td>
</tr>
</tbody>
</table>
<h2 data-number="2.3" id="customization-point-objects"><span class="header-section-number">2.3</span> Customization Point Objects<a href="#customization-point-objects" class="self-link"></a></h2>
<p>Customization Point Objects (CPOs) were designed to solve several of the above problems:</p>
<ol type="1">
<li>Provide an easy way to invoke the customized implementation. <code class="sourceCode cpp">ranges<span class="op">::</span>swap<span class="op">(</span>E, F<span class="op">)</span></code> just Does The Right Thing. ✔️.</li>
<li>Provide a way to to verify that a type implements the interface correctly, diagnosing some incorrect opt-ins. But it takes work. If a user provides a <code class="sourceCode cpp">begin</code> that returns <code class="sourceCode cpp"><span class="dt">void</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> will fail at that point. This is not as early a failure as we get with virtual member functions, but it’s at least earlier than we would otherwise get. But I’m not really open to giving a full check, since the way <code class="sourceCode cpp">ranges<span class="op">::</span>begin</code> does this verification is that the author of <code class="sourceCode cpp">ranges<span class="op">::</span>begin</code> has to manually write it.</li>
<li>Provide a name for the interface that makes it easier to verify, which addresses the issue of interface verification. As above, it is possible to provide, but it must be done manually.</li>
</ol>
<p>While <code class="sourceCode cpp">ranges<span class="op">::</span>begin</code> and <code class="sourceCode cpp">ranges<span class="op">::</span>end</code> do verify that those customization points properly return an iterator and a sentinel, and <code class="sourceCode cpp">ranges<span class="op">::</span>range</code> as a concept verifies the whole interface, the fact that everything about this interface is implicit still leads to inherently and fundamentally poor diagnostics. Consider:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">struct</span> R <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2"></a>    <span class="dt">void</span> begin<span class="op">()</span>;</span>
<span id="cb8-3"><a href="#cb8-3"></a>    <span class="dt">void</span> end<span class="op">()</span>;</span>
<span id="cb8-4"><a href="#cb8-4"></a><span class="op">}</span>;</span></code></pre></div>
<p>This type is not a <code class="sourceCode cpp">range</code>, obviously. But maybe I wanted it to be one and I didn’t realize that <code class="sourceCode cpp"><span class="dt">void</span></code> wasn’t an iterator. What do compilers tell me when I try to <code class="sourceCode cpp"><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>range<span class="op">&lt;</span>R<span class="op">&gt;)</span></code>?</p>
<p>msvc:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb9-1"><a href="#cb9-1"></a>&lt;source&gt;(8): error C2607: static assertion failed</span></code></pre></div>
<p>clang:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb10-1"><a href="#cb10-1"></a>&lt;source&gt;:8:1: error: static_assert failed</span>
<span id="cb10-2"><a href="#cb10-2"></a>static_assert(std::ranges::range&lt;R&gt;);</span>
<span id="cb10-3"><a href="#cb10-3"></a>^                          ~~~~~~~~</span>
<span id="cb10-4"><a href="#cb10-4"></a>&lt;source&gt;:8:28: note: because &#39;R&#39; does not satisfy &#39;range&#39;</span>
<span id="cb10-5"><a href="#cb10-5"></a>static_assert(std::ranges::range&lt;R&gt;);</span>
<span id="cb10-6"><a href="#cb10-6"></a>                           ^</span>
<span id="cb10-7"><a href="#cb10-7"></a>/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/11.0.0/../../../../include/c++/11.0.0/bits/ranges_base.h:581:2: note: because &#39;ranges::begin(__t)&#39; would be invalid: no matching function for call to object of type &#39;const __cust_access::_Begin&#39;</span>
<span id="cb10-8"><a href="#cb10-8"></a>        ranges::begin(__t);</span>
<span id="cb10-9"><a href="#cb10-9"></a>        ^</span></code></pre></div>
<p>gcc:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb11-1"><a href="#cb11-1"></a>&lt;source&gt;:8:28: error: static assertion failed</span>
<span id="cb11-2"><a href="#cb11-2"></a>    8 | static_assert(std::ranges::range&lt;R&gt;);</span>
<span id="cb11-3"><a href="#cb11-3"></a>      |               ~~~~~~~~~~~~~^~~~~~~~</span>
<span id="cb11-4"><a href="#cb11-4"></a>&lt;source&gt;:8:28: note: constraints not satisfied</span>
<span id="cb11-5"><a href="#cb11-5"></a>In file included from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/string_view:44,</span>
<span id="cb11-6"><a href="#cb11-6"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/basic_string.h:48,</span>
<span id="cb11-7"><a href="#cb11-7"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/string:55,</span>
<span id="cb11-8"><a href="#cb11-8"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/locale_classes.h:40,</span>
<span id="cb11-9"><a href="#cb11-9"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ios_base.h:41,</span>
<span id="cb11-10"><a href="#cb11-10"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/streambuf:41,</span>
<span id="cb11-11"><a href="#cb11-11"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/streambuf_iterator.h:35,</span>
<span id="cb11-12"><a href="#cb11-12"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/iterator:66,</span>
<span id="cb11-13"><a href="#cb11-13"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/ranges:43,</span>
<span id="cb11-14"><a href="#cb11-14"></a>                 from &lt;source&gt;:1:</span>
<span id="cb11-15"><a href="#cb11-15"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:579:13:   required by the constraints of &#39;template&lt;class _Tp&gt; concept std::ranges::range&#39;</span>
<span id="cb11-16"><a href="#cb11-16"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:579:21:   in requirements with &#39;_Tp&amp; __t&#39; [with _Tp = R]</span>
<span id="cb11-17"><a href="#cb11-17"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:581:22: note: the required expression &#39;std::ranges::__cust::begin(__t)&#39; is invalid</span>
<span id="cb11-18"><a href="#cb11-18"></a>  581 |         ranges::begin(__t);</span>
<span id="cb11-19"><a href="#cb11-19"></a>      |         ~~~~~~~~~~~~~^~~~~</span>
<span id="cb11-20"><a href="#cb11-20"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:582:20: note: the required expression &#39;std::ranges::__cust::end(__t)&#39; is invalid</span>
<span id="cb11-21"><a href="#cb11-21"></a>  582 |         ranges::end(__t);</span>
<span id="cb11-22"><a href="#cb11-22"></a>      |         ~~~~~~~~~~~^~~~~</span>
<span id="cb11-23"><a href="#cb11-23"></a>cc1plus: note: set &#39;-fconcepts-diagnostics-depth=&#39; to at least 2 for more detail</span></code></pre></div>
<p>If I crank up the diagnostics depth to 4 (2 is not enough), I finally get something about iterators in the 154 lines of diagnostic, reproduced here for clarity:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb12-1"><a href="#cb12-1"></a>&lt;source&gt;:8:28: error: static assertion failed</span>
<span id="cb12-2"><a href="#cb12-2"></a>    8 | static_assert(std::ranges::range&lt;R&gt;);</span>
<span id="cb12-3"><a href="#cb12-3"></a>      |               ~~~~~~~~~~~~~^~~~~~~~</span>
<span id="cb12-4"><a href="#cb12-4"></a>&lt;source&gt;:8:28: note: constraints not satisfied</span>
<span id="cb12-5"><a href="#cb12-5"></a>In file included from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/string_view:44,</span>
<span id="cb12-6"><a href="#cb12-6"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/basic_string.h:48,</span>
<span id="cb12-7"><a href="#cb12-7"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/string:55,</span>
<span id="cb12-8"><a href="#cb12-8"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/locale_classes.h:40,</span>
<span id="cb12-9"><a href="#cb12-9"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ios_base.h:41,</span>
<span id="cb12-10"><a href="#cb12-10"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/streambuf:41,</span>
<span id="cb12-11"><a href="#cb12-11"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/streambuf_iterator.h:35,</span>
<span id="cb12-12"><a href="#cb12-12"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/iterator:66,</span>
<span id="cb12-13"><a href="#cb12-13"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/ranges:43,</span>
<span id="cb12-14"><a href="#cb12-14"></a>                 from &lt;source&gt;:1:</span>
<span id="cb12-15"><a href="#cb12-15"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:579:13:   required by the constraints of &#39;template&lt;class _Tp&gt; concept std::ranges::range&#39;</span>
<span id="cb12-16"><a href="#cb12-16"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:579:21:   in requirements with &#39;_Tp&amp; __t&#39; [with _Tp = R]</span>
<span id="cb12-17"><a href="#cb12-17"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:581:22: note: the required expression &#39;std::ranges::__cust::begin(__t)&#39; is invalid, because</span>
<span id="cb12-18"><a href="#cb12-18"></a>  581 |         ranges::begin(__t);</span>
<span id="cb12-19"><a href="#cb12-19"></a>      |         ~~~~~~~~~~~~~^~~~~</span>
<span id="cb12-20"><a href="#cb12-20"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:581:22: error: no match for call to &#39;(const std::ranges::__cust_access::_Begin) (R&amp;)&#39;</span>
<span id="cb12-21"><a href="#cb12-21"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:117:9: note: candidate: &#39;template&lt;class _Tp&gt;  requires (__maybe_borrowed_range&lt;_Tp&gt;) &amp;&amp; ((is_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt;) || (__member_begin&lt;_Tp&gt;) || (__adl_begin&lt;_Tp&gt;)) constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&amp;&amp;) const&#39;</span>
<span id="cb12-22"><a href="#cb12-22"></a>  117 |         operator()(_Tp&amp;&amp; __t) const noexcept(_S_noexcept&lt;_Tp&gt;())</span>
<span id="cb12-23"><a href="#cb12-23"></a>      |         ^~~~~~~~</span>
<span id="cb12-24"><a href="#cb12-24"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:117:9: note:   template argument deduction/substitution failed:</span>
<span id="cb12-25"><a href="#cb12-25"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:117:9: note: constraints not satisfied</span>
<span id="cb12-26"><a href="#cb12-26"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h: In substitution of &#39;template&lt;class _Tp&gt;  requires (__maybe_borrowed_range&lt;_Tp&gt;) &amp;&amp; ((is_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt;) || (__member_begin&lt;_Tp&gt;) || (__adl_begin&lt;_Tp&gt;)) constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&amp;&amp;) const [with _Tp = R&amp;]&#39;:</span>
<span id="cb12-27"><a href="#cb12-27"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:581:15:   required from here</span>
<span id="cb12-28"><a href="#cb12-28"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:117:2:   required by the constraints of &#39;template&lt;class _Tp&gt;  requires (__maybe_borrowed_range&lt;_Tp&gt;) &amp;&amp; ((is_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt;) || (__member_begin&lt;_Tp&gt;) || (__adl_begin&lt;_Tp&gt;)) constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&amp;&amp;) const&#39;</span>
<span id="cb12-29"><a href="#cb12-29"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:115:11: note: no operand of the disjunction is satisfied</span>
<span id="cb12-30"><a href="#cb12-30"></a>  114 |         requires is_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_begin&lt;_Tp&gt;</span>
<span id="cb12-31"><a href="#cb12-31"></a>      |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-32"><a href="#cb12-32"></a>  115 |           || __adl_begin&lt;_Tp&gt;</span>
<span id="cb12-33"><a href="#cb12-33"></a>      |           ^~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-34"><a href="#cb12-34"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:114:18: note: the operand &#39;is_array_v&lt;std::remove_reference_t&lt;_Tp&gt; &gt;&#39; is unsatisfied because</span>
<span id="cb12-35"><a href="#cb12-35"></a>  114 |         requires is_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_begin&lt;_Tp&gt;</span>
<span id="cb12-36"><a href="#cb12-36"></a>      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-37"><a href="#cb12-37"></a>  115 |           || __adl_begin&lt;_Tp&gt;</span>
<span id="cb12-38"><a href="#cb12-38"></a>      |           ~~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-39"><a href="#cb12-39"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:117:2:   required by the constraints of &#39;template&lt;class _Tp&gt;  requires (__maybe_borrowed_range&lt;_Tp&gt;) &amp;&amp; ((is_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt;) || (__member_begin&lt;_Tp&gt;) || (__adl_begin&lt;_Tp&gt;)) constexpr auto std::ranges::__cust_access::_Begin::operator()(_Tp&amp;&amp;) const&#39;</span>
<span id="cb12-40"><a href="#cb12-40"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:114:18: note: the expression &#39;is_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt; [with _Tp = R&amp;]&#39; evaluated to &#39;false&#39;</span>
<span id="cb12-41"><a href="#cb12-41"></a>  114 |         requires is_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_begin&lt;_Tp&gt;</span>
<span id="cb12-42"><a href="#cb12-42"></a>      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-43"><a href="#cb12-43"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:114:57: note: the operand &#39;__member_begin&lt;_Tp&gt;&#39; is unsatisfied because</span>
<span id="cb12-44"><a href="#cb12-44"></a>  114 |         requires is_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_begin&lt;_Tp&gt;</span>
<span id="cb12-45"><a href="#cb12-45"></a>      |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-46"><a href="#cb12-46"></a>  115 |           || __adl_begin&lt;_Tp&gt;</span>
<span id="cb12-47"><a href="#cb12-47"></a>      |           ~~~~~~~~~~~~~~~~~~~                            </span>
<span id="cb12-48"><a href="#cb12-48"></a>In file included from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/stl_iterator_base_types.h:71,</span>
<span id="cb12-49"><a href="#cb12-49"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/iterator:61,</span>
<span id="cb12-50"><a href="#cb12-50"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/ranges:43,</span>
<span id="cb12-51"><a href="#cb12-51"></a>                 from &lt;source&gt;:1:</span>
<span id="cb12-52"><a href="#cb12-52"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/iterator_concepts.h:937:15:   required for the satisfaction of &#39;__member_begin&lt;_Tp&gt;&#39; [with _Tp = R&amp;]</span>
<span id="cb12-53"><a href="#cb12-53"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/iterator_concepts.h:937:32:   in requirements with &#39;_Tp&amp; __t&#39; [with _Tp = R&amp;]</span>
<span id="cb12-54"><a href="#cb12-54"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/iterator_concepts.h:939:35: note: the required expression &#39;std::__detail::__decay_copy(__t.begin())&#39; is invalid, because</span>
<span id="cb12-55"><a href="#cb12-55"></a>  939 |           { __detail::__decay_copy(__t.begin()) } -&gt; input_or_output_iterator;</span>
<span id="cb12-56"><a href="#cb12-56"></a>      |             ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~</span>
<span id="cb12-57"><a href="#cb12-57"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/iterator_concepts.h:939:45: error: invalid use of void expression</span>
<span id="cb12-58"><a href="#cb12-58"></a>  939 |           { __detail::__decay_copy(__t.begin()) } -&gt; input_or_output_iterator;</span>
<span id="cb12-59"><a href="#cb12-59"></a>      |                                    ~~~~~~~~~^~</span>
<span id="cb12-60"><a href="#cb12-60"></a>In file included from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/string_view:44,</span>
<span id="cb12-61"><a href="#cb12-61"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/basic_string.h:48,</span>
<span id="cb12-62"><a href="#cb12-62"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/string:55,</span>
<span id="cb12-63"><a href="#cb12-63"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/locale_classes.h:40,</span>
<span id="cb12-64"><a href="#cb12-64"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ios_base.h:41,</span>
<span id="cb12-65"><a href="#cb12-65"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/streambuf:41,</span>
<span id="cb12-66"><a href="#cb12-66"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/streambuf_iterator.h:35,</span>
<span id="cb12-67"><a href="#cb12-67"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/iterator:66,</span>
<span id="cb12-68"><a href="#cb12-68"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/ranges:43,</span>
<span id="cb12-69"><a href="#cb12-69"></a>                 from &lt;source&gt;:1:</span>
<span id="cb12-70"><a href="#cb12-70"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:115:14: note: the operand &#39;__adl_begin&lt;_Tp&gt;&#39; is unsatisfied because</span>
<span id="cb12-71"><a href="#cb12-71"></a>  114 |         requires is_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_begin&lt;_Tp&gt;</span>
<span id="cb12-72"><a href="#cb12-72"></a>      |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-73"><a href="#cb12-73"></a>  115 |           || __adl_begin&lt;_Tp&gt;</span>
<span id="cb12-74"><a href="#cb12-74"></a>      |           ~~~^~~~~~~~~~~~~~~~</span>
<span id="cb12-75"><a href="#cb12-75"></a>In file included from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/stl_iterator_base_types.h:71,</span>
<span id="cb12-76"><a href="#cb12-76"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/iterator:61,</span>
<span id="cb12-77"><a href="#cb12-77"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/ranges:43,</span>
<span id="cb12-78"><a href="#cb12-78"></a>                 from &lt;source&gt;:1:</span>
<span id="cb12-79"><a href="#cb12-79"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/iterator_concepts.h:946:15:   required for the satisfaction of &#39;__adl_begin&lt;_Tp&gt;&#39; [with _Tp = R&amp;]</span>
<span id="cb12-80"><a href="#cb12-80"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/iterator_concepts.h:947:5:   in requirements with &#39;_Tp&amp; __t&#39; [with _Tp = R&amp;]</span>
<span id="cb12-81"><a href="#cb12-81"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/iterator_concepts.h:949:35: note: the required expression &#39;std::__detail::__decay_copy(std::__detail::begin(__t))&#39; is invalid, because</span>
<span id="cb12-82"><a href="#cb12-82"></a>  949 |           { __detail::__decay_copy(begin(__t)) } -&gt; input_or_output_iterator;</span>
<span id="cb12-83"><a href="#cb12-83"></a>      |             ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~</span>
<span id="cb12-84"><a href="#cb12-84"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/iterator_concepts.h:949:41: error: use of deleted function &#39;void std::__detail::begin(auto:1&amp;) [with auto:1 = R]&#39;</span>
<span id="cb12-85"><a href="#cb12-85"></a>  949 |           { __detail::__decay_copy(begin(__t)) } -&gt; input_or_output_iterator;</span>
<span id="cb12-86"><a href="#cb12-86"></a>      |                                    ~~~~~^~~~~</span>
<span id="cb12-87"><a href="#cb12-87"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/iterator_concepts.h:942:10: note: declared here</span>
<span id="cb12-88"><a href="#cb12-88"></a>  942 |     void begin(auto&amp;) = delete;</span>
<span id="cb12-89"><a href="#cb12-89"></a>      |          ^~~~~</span>
<span id="cb12-90"><a href="#cb12-90"></a>In file included from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/string_view:44,</span>
<span id="cb12-91"><a href="#cb12-91"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/basic_string.h:48,</span>
<span id="cb12-92"><a href="#cb12-92"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/string:55,</span>
<span id="cb12-93"><a href="#cb12-93"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/locale_classes.h:40,</span>
<span id="cb12-94"><a href="#cb12-94"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ios_base.h:41,</span>
<span id="cb12-95"><a href="#cb12-95"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/streambuf:41,</span>
<span id="cb12-96"><a href="#cb12-96"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/streambuf_iterator.h:35,</span>
<span id="cb12-97"><a href="#cb12-97"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/iterator:66,</span>
<span id="cb12-98"><a href="#cb12-98"></a>                 from /opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/ranges:43,</span>
<span id="cb12-99"><a href="#cb12-99"></a>                 from &lt;source&gt;:1:</span>
<span id="cb12-100"><a href="#cb12-100"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:582:20: note: the required expression &#39;std::ranges::__cust::end(__t)&#39; is invalid, because</span>
<span id="cb12-101"><a href="#cb12-101"></a>  582 |         ranges::end(__t);</span>
<span id="cb12-102"><a href="#cb12-102"></a>      |         ~~~~~~~~~~~^~~~~</span>
<span id="cb12-103"><a href="#cb12-103"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:582:20: error: no match for call to &#39;(const std::ranges::__cust_access::_End) (R&amp;)&#39;</span>
<span id="cb12-104"><a href="#cb12-104"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:171:9: note: candidate: &#39;template&lt;class _Tp&gt;  requires (__maybe_borrowed_range&lt;_Tp&gt;) &amp;&amp; ((is_bounded_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt;) || (__member_end&lt;_Tp&gt;) || (__adl_end&lt;_Tp&gt;)) constexpr auto std::ranges::__cust_access::_End::operator()(_Tp&amp;&amp;) const&#39;</span>
<span id="cb12-105"><a href="#cb12-105"></a>  171 |         operator()(_Tp&amp;&amp; __t) const noexcept(_S_noexcept&lt;_Tp&gt;())</span>
<span id="cb12-106"><a href="#cb12-106"></a>      |         ^~~~~~~~</span>
<span id="cb12-107"><a href="#cb12-107"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:171:9: note:   template argument deduction/substitution failed:</span>
<span id="cb12-108"><a href="#cb12-108"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:171:9: note: constraints not satisfied</span>
<span id="cb12-109"><a href="#cb12-109"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h: In substitution of &#39;template&lt;class _Tp&gt;  requires (__maybe_borrowed_range&lt;_Tp&gt;) &amp;&amp; ((is_bounded_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt;) || (__member_end&lt;_Tp&gt;) || (__adl_end&lt;_Tp&gt;)) constexpr auto std::ranges::__cust_access::_End::operator()(_Tp&amp;&amp;) const [with _Tp = R&amp;]&#39;:</span>
<span id="cb12-110"><a href="#cb12-110"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:582:13:   required from here</span>
<span id="cb12-111"><a href="#cb12-111"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:171:2:   required by the constraints of &#39;template&lt;class _Tp&gt;  requires (__maybe_borrowed_range&lt;_Tp&gt;) &amp;&amp; ((is_bounded_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt;) || (__member_end&lt;_Tp&gt;) || (__adl_end&lt;_Tp&gt;)) constexpr auto std::ranges::__cust_access::_End::operator()(_Tp&amp;&amp;) const&#39;</span>
<span id="cb12-112"><a href="#cb12-112"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:169:9: note: no operand of the disjunction is satisfied</span>
<span id="cb12-113"><a href="#cb12-113"></a>  168 |         requires is_bounded_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_end&lt;_Tp&gt;</span>
<span id="cb12-114"><a href="#cb12-114"></a>      |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-115"><a href="#cb12-115"></a>  169 |         || __adl_end&lt;_Tp&gt;</span>
<span id="cb12-116"><a href="#cb12-116"></a>      |         ^~~~~~~~~~~~~~~~~</span>
<span id="cb12-117"><a href="#cb12-117"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:168:18: note: the operand &#39;is_bounded_array_v&lt;std::remove_reference_t&lt;_Tp&gt; &gt;&#39; is unsatisfied because</span>
<span id="cb12-118"><a href="#cb12-118"></a>  168 |         requires is_bounded_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_end&lt;_Tp&gt;</span>
<span id="cb12-119"><a href="#cb12-119"></a>      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-120"><a href="#cb12-120"></a>  169 |         || __adl_end&lt;_Tp&gt;</span>
<span id="cb12-121"><a href="#cb12-121"></a>      |         ~~~~~~~~~~~~~~~~~</span>
<span id="cb12-122"><a href="#cb12-122"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:171:2:   required by the constraints of &#39;template&lt;class _Tp&gt;  requires (__maybe_borrowed_range&lt;_Tp&gt;) &amp;&amp; ((is_bounded_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt;) || (__member_end&lt;_Tp&gt;) || (__adl_end&lt;_Tp&gt;)) constexpr auto std::ranges::__cust_access::_End::operator()(_Tp&amp;&amp;) const&#39;</span>
<span id="cb12-123"><a href="#cb12-123"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:168:18: note: the expression &#39;is_bounded_array_v&lt;typename std::remove_reference&lt;_Tp&gt;::type&gt; [with _Tp = R&amp;]&#39; evaluated to &#39;false&#39;</span>
<span id="cb12-124"><a href="#cb12-124"></a>  168 |         requires is_bounded_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_end&lt;_Tp&gt;</span>
<span id="cb12-125"><a href="#cb12-125"></a>      |                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-126"><a href="#cb12-126"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:168:65: note: the operand &#39;__member_end&lt;_Tp&gt;&#39; is unsatisfied because</span>
<span id="cb12-127"><a href="#cb12-127"></a>  168 |         requires is_bounded_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_end&lt;_Tp&gt;</span>
<span id="cb12-128"><a href="#cb12-128"></a>      |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~</span>
<span id="cb12-129"><a href="#cb12-129"></a>  169 |         || __adl_end&lt;_Tp&gt;</span>
<span id="cb12-130"><a href="#cb12-130"></a>      |         ~~~~~~~~~~~~~~~~~                                        </span>
<span id="cb12-131"><a href="#cb12-131"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:134:15:   required for the satisfaction of &#39;__member_end&lt;_Tp&gt;&#39; [with _Tp = R&amp;]</span>
<span id="cb12-132"><a href="#cb12-132"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:134:30:   in requirements with &#39;_Tp&amp; __t&#39; [with _Tp = R&amp;]</span>
<span id="cb12-133"><a href="#cb12-133"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:136:25: note: the required expression &#39;std::__detail::__decay_copy(__t.end())&#39; is invalid, because</span>
<span id="cb12-134"><a href="#cb12-134"></a>  136 |           { __decay_copy(__t.end()) }</span>
<span id="cb12-135"><a href="#cb12-135"></a>      |             ~~~~~~~~~~~~^~~~~~~~~~~</span>
<span id="cb12-136"><a href="#cb12-136"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:136:33: error: invalid use of void expression</span>
<span id="cb12-137"><a href="#cb12-137"></a>  136 |           { __decay_copy(__t.end()) }</span>
<span id="cb12-138"><a href="#cb12-138"></a>      |                          ~~~~~~~^~</span>
<span id="cb12-139"><a href="#cb12-139"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:169:12: note: the operand &#39;__adl_end&lt;_Tp&gt;&#39; is unsatisfied because</span>
<span id="cb12-140"><a href="#cb12-140"></a>  168 |         requires is_bounded_array_v&lt;remove_reference_t&lt;_Tp&gt;&gt; || __member_end&lt;_Tp&gt;</span>
<span id="cb12-141"><a href="#cb12-141"></a>      |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb12-142"><a href="#cb12-142"></a>  169 |         || __adl_end&lt;_Tp&gt;</span>
<span id="cb12-143"><a href="#cb12-143"></a>      |         ~~~^~~~~~~~~~~~~~</span>
<span id="cb12-144"><a href="#cb12-144"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:144:15:   required for the satisfaction of &#39;__adl_end&lt;_Tp&gt;&#39; [with _Tp = R&amp;]</span>
<span id="cb12-145"><a href="#cb12-145"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:145:5:   in requirements with &#39;_Tp&amp; __t&#39; [with _Tp = R&amp;]</span>
<span id="cb12-146"><a href="#cb12-146"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:147:25: note: the required expression &#39;std::__detail::__decay_copy(std::ranges::__cust_access::end(__t))&#39; is invalid, because</span>
<span id="cb12-147"><a href="#cb12-147"></a>  147 |           { __decay_copy(end(__t)) }</span>
<span id="cb12-148"><a href="#cb12-148"></a>      |             ~~~~~~~~~~~~^~~~~~~~~~</span>
<span id="cb12-149"><a href="#cb12-149"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:147:29: error: use of deleted function &#39;void std::ranges::__cust_access::end(auto:3&amp;) [with auto:3 = R]&#39;</span>
<span id="cb12-150"><a href="#cb12-150"></a>  147 |           { __decay_copy(end(__t)) }</span>
<span id="cb12-151"><a href="#cb12-151"></a>      |                          ~~~^~~~~</span>
<span id="cb12-152"><a href="#cb12-152"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/bits/ranges_base.h:140:10: note: declared here</span>
<span id="cb12-153"><a href="#cb12-153"></a>  140 |     void end(auto&amp;) = delete;</span>
<span id="cb12-154"><a href="#cb12-154"></a>      |          ^~~</span></code></pre></div>
<p>The issue here is explicitness. We have no idea if some random <code class="sourceCode cpp">begin</code> function we found is intended to be <em>the</em> entry point for <code class="sourceCode cpp">range</code> or not, so we don’t know if a non-matching <code class="sourceCode cpp">begin</code> (whether the arguments don’t line up or, as in this case, the return type doesn’t meet requirements) is meaningful to diagnose or not.</p>
<p>This case might seem silly but it’s actually very serious. Consider an example where instead of an “obvious” failure like trying to use <code class="sourceCode cpp"><span class="dt">void</span></code> as an iterator, I actually had what I thought was a valid iterator, but was missing one operation or other (maybe it was missing postfix <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">++</span></code>, or its <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">*()</span></code> was not const-qualified?)? I’d get the exact same diagnostic: hundreds of lines of diagnostic, which simply <em>cannot</em> point to the problem.</p>
<p>It might seem that the single-line MSVC diagnostic of “static assertion failed” is something that reflects negatively on MSVC. But honestly, gcc’s 154-line diagnostic when I crank up the diagnostic depth doesn’t really provide me any meaningful information either.</p>
<p>All of which is to say, I’m only giving 🤷s to CPOs for verification.</p>
<p>Associated types are an interesting question for CPOs in their own right. Because it now becomes easy to invoke the right customization point, it also becomes easy to inspect those customization points. For instance, Ranges comes with type traits for the iterator and sentinel type of a range:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> T<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2"></a>  <span class="kw">using</span> iterator_t <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>begin<span class="op">(</span>declval<span class="op">&lt;</span>T<span class="op">&amp;&gt;()))</span>;</span>
<span id="cb13-3"><a href="#cb13-3"></a><span class="kw">template</span><span class="op">&lt;</span>range R<span class="op">&gt;</span></span>
<span id="cb13-4"><a href="#cb13-4"></a>  <span class="kw">using</span> sentinel_t <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>end<span class="op">(</span>declval<span class="op">&lt;</span>R<span class="op">&amp;&gt;()))</span>;</span></code></pre></div>
<p>It’s very convenient to have type traits to get these associated types, and these are highly important in ranges code. But it also means that we have a proliferation of type traits (Ranges alone has seven), which makes the API surface of the library absolutely enormous. So I’m going to give this a 🤷 as well.</p>
<p>Let’s take a different interface. Let’s say instead of Ranges and Iterators, we wanted to do equality. We’ll have two functions: <code class="sourceCode cpp">eq</code> and <code class="sourceCode cpp">ne</code>. <code class="sourceCode cpp">eq</code> must be customized to take two <code class="sourceCode cpp">T <span class="kw">const</span><span class="op">&amp;</span></code>s and return <code class="sourceCode cpp"><span class="dt">bool</span></code>. <code class="sourceCode cpp">ne</code> can be customized, but doesn’t have to be, and defaults to negating the result of <code class="sourceCode cpp">eq</code>. As a CPO, this would look something like this (where my library is <code class="sourceCode cpp">N</code>):</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1"></a><span class="kw">namespace</span> N<span class="op">::</span>hidden <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb14-3"><a href="#cb14-3"></a>    <span class="kw">concept</span> has_eq <span class="op">=</span> <span class="kw">requires</span> <span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> v<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-4"><a href="#cb14-4"></a>        <span class="op">{</span> eq<span class="op">(</span>v, v<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>same_as<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span>;</span>
<span id="cb14-5"><a href="#cb14-5"></a>    <span class="op">}</span>;</span>
<span id="cb14-6"><a href="#cb14-6"></a></span>
<span id="cb14-7"><a href="#cb14-7"></a>    <span class="kw">struct</span> eq_fn <span class="op">{</span></span>
<span id="cb14-8"><a href="#cb14-8"></a>        <span class="kw">template</span> <span class="op">&lt;</span>has_eq T<span class="op">&gt;</span></span>
<span id="cb14-9"><a href="#cb14-9"></a>        <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">()(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb14-10"><a href="#cb14-10"></a>            <span class="cf">return</span> eq<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb14-11"><a href="#cb14-11"></a>        <span class="op">}</span></span>
<span id="cb14-12"><a href="#cb14-12"></a>    <span class="op">}</span>;</span>
<span id="cb14-13"><a href="#cb14-13"></a>  </span>
<span id="cb14-14"><a href="#cb14-14"></a>    <span class="kw">template</span> <span class="op">&lt;</span>has_eq T<span class="op">&gt;</span></span>
<span id="cb14-15"><a href="#cb14-15"></a>    <span class="kw">constexpr</span> <span class="dt">bool</span> ne<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-16"><a href="#cb14-16"></a>        <span class="cf">return</span> <span class="kw">not</span> eq<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb14-17"><a href="#cb14-17"></a>    <span class="op">}</span></span>
<span id="cb14-18"><a href="#cb14-18"></a>  </span>
<span id="cb14-19"><a href="#cb14-19"></a>    <span class="kw">struct</span> ne_fn <span class="op">{</span></span>
<span id="cb14-20"><a href="#cb14-20"></a>        <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb14-21"><a href="#cb14-21"></a>            <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> v<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-22"><a href="#cb14-22"></a>                <span class="op">{</span> ne<span class="op">(</span>v, v<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> std<span class="op">::</span>same_as<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span>;</span>
<span id="cb14-23"><a href="#cb14-23"></a>            <span class="op">}</span></span>
<span id="cb14-24"><a href="#cb14-24"></a>        <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">()(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb14-25"><a href="#cb14-25"></a>            <span class="cf">return</span> ne<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb14-26"><a href="#cb14-26"></a>        <span class="op">}</span></span>
<span id="cb14-27"><a href="#cb14-27"></a>    <span class="op">}</span>;</span>
<span id="cb14-28"><a href="#cb14-28"></a><span class="op">}</span></span>
<span id="cb14-29"><a href="#cb14-29"></a></span>
<span id="cb14-30"><a href="#cb14-30"></a><span class="kw">namespace</span> N <span class="op">{</span></span>
<span id="cb14-31"><a href="#cb14-31"></a>    <span class="kw">inline</span> <span class="kw">namespace</span> cpos <span class="op">{</span></span>
<span id="cb14-32"><a href="#cb14-32"></a>        <span class="kw">inline</span> <span class="kw">constexpr</span> hidden<span class="op">::</span>eq_fn eq<span class="op">{}</span>;</span>
<span id="cb14-33"><a href="#cb14-33"></a>        <span class="kw">inline</span> <span class="kw">constexpr</span> hidden<span class="op">::</span>ne_fn ne<span class="op">{}</span>;</span>
<span id="cb14-34"><a href="#cb14-34"></a>    <span class="op">}</span></span>
<span id="cb14-35"><a href="#cb14-35"></a>    </span>
<span id="cb14-36"><a href="#cb14-36"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb14-37"><a href="#cb14-37"></a>    <span class="kw">concept</span> equality_comparable <span class="op">=</span></span>
<span id="cb14-38"><a href="#cb14-38"></a>        <span class="kw">requires</span> <span class="op">(</span>std<span class="op">::</span>remove_reference_t<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-39"><a href="#cb14-39"></a>            eq<span class="op">(</span>t, t<span class="op">)</span>;</span>
<span id="cb14-40"><a href="#cb14-40"></a>            ne<span class="op">(</span>t, t<span class="op">)</span>;</span>
<span id="cb14-41"><a href="#cb14-41"></a>        <span class="op">}</span>;</span>
<span id="cb14-42"><a href="#cb14-42"></a><span class="op">}</span></span></code></pre></div>
<p>This is 42 lines of code.</p>
<p>It’s worth reiterating that this is substantially better than raw ADL - if you just use <code class="sourceCode cpp">N<span class="op">::</span>eq</code> and <code class="sourceCode cpp">N<span class="op">::</span>ne</code> everywhere, you don’t have to worry about issues like calling the wrong thing (perhaps some type has a more efficient inequality than simply negating equality? <code class="sourceCode cpp">N<span class="op">::</span>ne</code> will do the right thing) or it being an invalid implementation (perhaps the user’s implementation accidentally took references to non-const and mutated the arguments? This wouldn’t compile). But this is not easy to write, and for such a straightforward interface, you can’t really tell what it is anyway without some serious study. In this case, I didn’t bother with the member/non-member rigamarole and only provided non-member opt-in. Providing member opt-in as well has some real cost in terms of both implementation complexity and diagnostics, so I’m sticking with the simple version for now.</p>
<p>CPOs improve upon just raw ADL names by allowing you to verify more things. While they provide the user a way to ensure they call the correct implementation and provide checking for the user that they implemented the customization point correctly (to some extent), that comes with a cost: somebody had to write all of that by hand, and it’s not necessarily cheap to compile either. Even though we’re addressing more of the customization facilities that I’m claiming we want, these are much harder and time-consuming interfaces to write.. that nevertheless are quite opaque.</p>
<table>
<thead>
<tr class="header">
<th></th>
<th><div style="text-align:center">
<strong><code class="sourceCode cpp"><span class="kw">virtual</span></code> <br />member functions</strong>
</div></th>
<th><div style="text-align:center">
<strong>class template<br />specialization</strong>
</div></th>
<th><div style="text-align:center">
<strong>Pure<br />ADL</strong>
</div></th>
<th><div style="text-align:center">
<strong>CPOs</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Interface visible in code</td>
<td>✔️</td>
<td>❌</td>
<td>❌</td>
<td>❌</td>
</tr>
<tr class="even">
<td>Providing default implementations</td>
<td>✔️</td>
<td>❌</td>
<td>✔️</td>
<td>✔️</td>
</tr>
<tr class="odd">
<td>Explicit opt-in</td>
<td>✔️</td>
<td>✔️</td>
<td>❌</td>
<td>❌</td>
</tr>
<tr class="even">
<td>Diagnose incorrect opt-in</td>
<td>✔️</td>
<td>❌</td>
<td>❌</td>
<td>🤷</td>
</tr>
<tr class="odd">
<td>Easily invoke the customization</td>
<td>✔️</td>
<td>🤷</td>
<td>❌</td>
<td>✔️</td>
</tr>
<tr class="even">
<td>Verify implementation</td>
<td>✔️</td>
<td>❌</td>
<td>❌</td>
<td>🤷</td>
</tr>
<tr class="odd">
<td>Atomic grouping of functionality</td>
<td>✔️</td>
<td>🤷</td>
<td>❌</td>
<td>❌</td>
</tr>
<tr class="even">
<td>Non-intrusive</td>
<td>❌</td>
<td>✔️</td>
<td>✔️</td>
<td>✔️</td>
</tr>
<tr class="odd">
<td>Associated Types</td>
<td>❌</td>
<td>🤷</td>
<td>❌</td>
<td>🤷</td>
</tr>
</tbody>
</table>
<h2 data-number="2.4" id="tag_invoke"><span class="header-section-number">2.4</span> <code class="sourceCode cpp">tag_invoke</code><a href="#tag_invoke" class="self-link"></a></h2>
<p>The <code class="sourceCode cpp">tag_invoke</code> paper (<span class="citation" data-cites="P1895R0">[<a href="#ref-P1895R0" role="doc-biblioref">P1895R0</a>]</span>) lays out two issues with Customization Point Objects (more broadly ADL-based customization points at large):</p>
<ol type="1">
<li>ADL requires globally reserving the identifier. You can’t have two different libraries using <code class="sourceCode cpp">begin</code> as a customization point, really. Ranges claimed it decades ago.</li>
<li>ADL can’t allow writing wrapper types that are transparent to customization.</li>
</ol>
<p>This paper will discuss the second issue later. Instead I’ll focus on the first point. This is an unequivocally real and serious issue. C++, unlike C, has namespaces, and we’d like to be able to take advantage that when it comes to customization. But ADL, very much by design, isn’t bound by namespace. With virtual member functions, there are no issues with having <code class="sourceCode cpp">libA<span class="op">::</span>Interface</code> and <code class="sourceCode cpp">libB<span class="op">::</span>Interface</code> coexist (only if both provide virtual member functions of the same name and take the same parameters and a type wants to implement both). Likewise with class template specializations - specializing one name in one namespace has nothing to do with specializing a similarly-spelled name in a different namespace. But if <code class="sourceCode cpp">libA</code> and <code class="sourceCode cpp">libB</code> decide that they both want ADL customization points named <code class="sourceCode cpp">eq</code>? You better hope their arguments are sufficiently distinct or you simply cannot use both libraries.</p>
<p>The goal of <code class="sourceCode cpp">tag_invoke</code> is to instead globally reserve a single name: <code class="sourceCode cpp">tag_invoke</code>. Not likely to have been used much before the introduction of this paper.</p>
<p>The implementation of the <code class="sourceCode cpp">eq</code> interface introduced above in the <code class="sourceCode cpp">tag_invoke</code> model would look as follows:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1"></a><span class="kw">namespace</span> N <span class="op">{</span></span>
<span id="cb15-2"><a href="#cb15-2"></a>    <span class="kw">struct</span> eq_fn <span class="op">{</span></span>
<span id="cb15-3"><a href="#cb15-3"></a>        <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb15-4"><a href="#cb15-4"></a>            <span class="kw">requires</span> std<span class="op">::</span>same_as<span class="op">&lt;</span></span>
<span id="cb15-5"><a href="#cb15-5"></a>                std<span class="op">::</span>tag_invoke_result_t<span class="op">&lt;</span>eq_fn, T <span class="kw">const</span><span class="op">&amp;</span>, T <span class="kw">const</span><span class="op">&amp;&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span></span>
<span id="cb15-6"><a href="#cb15-6"></a>        <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">()(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb15-7"><a href="#cb15-7"></a>            <span class="cf">return</span> std<span class="op">::</span>tag_invoke<span class="op">(*</span><span class="kw">this</span>, x, y<span class="op">)</span>;</span>
<span id="cb15-8"><a href="#cb15-8"></a>        <span class="op">}</span></span>
<span id="cb15-9"><a href="#cb15-9"></a>    <span class="op">}</span>;</span>
<span id="cb15-10"><a href="#cb15-10"></a>  </span>
<span id="cb15-11"><a href="#cb15-11"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> eq_fn eq<span class="op">{}</span>;</span>
<span id="cb15-12"><a href="#cb15-12"></a>  </span>
<span id="cb15-13"><a href="#cb15-13"></a>    <span class="kw">struct</span> ne_fn <span class="op">{</span></span>
<span id="cb15-14"><a href="#cb15-14"></a>        <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb15-15"><a href="#cb15-15"></a>            <span class="kw">requires</span> std<span class="op">::</span>invocable<span class="op">&lt;</span>eq_fn, T <span class="kw">const</span><span class="op">&amp;</span>, T <span class="kw">const</span><span class="op">&amp;&gt;</span></span>
<span id="cb15-16"><a href="#cb15-16"></a>        <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> tag_invoke<span class="op">(</span>ne_fn, T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb15-17"><a href="#cb15-17"></a>            <span class="cf">return</span> <span class="kw">not</span> eq<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb15-18"><a href="#cb15-18"></a>        <span class="op">}</span></span>
<span id="cb15-19"><a href="#cb15-19"></a>  </span>
<span id="cb15-20"><a href="#cb15-20"></a>        <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb15-21"><a href="#cb15-21"></a>            <span class="kw">requires</span> std<span class="op">::</span>same_as<span class="op">&lt;</span></span>
<span id="cb15-22"><a href="#cb15-22"></a>                std<span class="op">::</span>tag_invoke_result_t<span class="op">&lt;</span>ne_fn, T <span class="kw">const</span><span class="op">&amp;</span>, T <span class="kw">const</span><span class="op">&amp;&gt;</span>, <span class="dt">bool</span><span class="op">&gt;</span></span>
<span id="cb15-23"><a href="#cb15-23"></a>        <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">()(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb15-24"><a href="#cb15-24"></a>            <span class="cf">return</span> std<span class="op">::</span>tag_invoke<span class="op">(*</span><span class="kw">this</span>, x, y<span class="op">)</span>;</span>
<span id="cb15-25"><a href="#cb15-25"></a>        <span class="op">}</span></span>
<span id="cb15-26"><a href="#cb15-26"></a>    <span class="op">}</span>;</span>
<span id="cb15-27"><a href="#cb15-27"></a>  </span>
<span id="cb15-28"><a href="#cb15-28"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> ne_fn ne<span class="op">{}</span>;</span>
<span id="cb15-29"><a href="#cb15-29"></a>  </span>
<span id="cb15-30"><a href="#cb15-30"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb15-31"><a href="#cb15-31"></a>    <span class="kw">concept</span> equality_comparable <span class="op">=</span></span>
<span id="cb15-32"><a href="#cb15-32"></a>        <span class="kw">requires</span> <span class="op">(</span>std<span class="op">::</span>remove_reference_t<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb15-33"><a href="#cb15-33"></a>            eq<span class="op">(</span>t, t<span class="op">)</span>;</span>
<span id="cb15-34"><a href="#cb15-34"></a>            ne<span class="op">(</span>t, t<span class="op">)</span>;</span>
<span id="cb15-35"><a href="#cb15-35"></a>        <span class="op">}</span>;  </span>
<span id="cb15-36"><a href="#cb15-36"></a><span class="op">}</span></span></code></pre></div>
<p>This is 36 lines of code.</p>
<p>To what extent does this <code class="sourceCode cpp">tag_invoke</code>-based implementation of <code class="sourceCode cpp">eq</code> and <code class="sourceCode cpp">ne</code> address the customization facilities that regular CPOs fall short on? It does help: we can now explicitly opt into the interface (indeed, the only way to opt-in is explicit) ✔️!</p>
<p>But the above is harder to write for the library author (I am unconvinced by the claims that this is easier or simpler) and it is harder to understand the interface from looking at the code (before, the objects clearly invoked <code class="sourceCode cpp">eq</code> and <code class="sourceCode cpp">ne</code>, respectively, that is no longer the case). When users opt-in for their own types, the opt-in is improved by being explicit but takes some getting used to:</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1"></a><span class="kw">struct</span> Widget <span class="op">{</span></span>
<span id="cb16-2"><a href="#cb16-2"></a>  <span class="dt">int</span> i;</span>
<span id="cb16-3"><a href="#cb16-3"></a>  </span>
<span id="cb16-4"><a href="#cb16-4"></a>  <span class="co">// with CPO: just some function named eq</span></span>
<span id="cb16-5"><a href="#cb16-5"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="dt">bool</span> eq<span class="op">(</span>Widget a, Widget b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-6"><a href="#cb16-6"></a>    <span class="cf">return</span> a<span class="op">.</span>i <span class="op">==</span> b<span class="op">.</span>i;</span>
<span id="cb16-7"><a href="#cb16-7"></a>  <span class="op">}</span></span>
<span id="cb16-8"><a href="#cb16-8"></a>  </span>
<span id="cb16-9"><a href="#cb16-9"></a>  <span class="co">// with tag_invoke: we are visibly opting</span></span>
<span id="cb16-10"><a href="#cb16-10"></a>  <span class="co">// into support for N::eq</span></span>
<span id="cb16-11"><a href="#cb16-11"></a>  <span class="kw">constexpr</span> <span class="kw">friend</span> <span class="dt">bool</span> tag_invoke<span class="op">(</span>std<span class="op">::</span>tag_t<span class="op">&lt;</span>N<span class="op">::</span>eq<span class="op">&gt;</span>, Widget a, Widget b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-12"><a href="#cb16-12"></a>    <span class="cf">return</span> a<span class="op">.</span>i <span class="op">==</span> b<span class="op">.</span>i;</span>
<span id="cb16-13"><a href="#cb16-13"></a>  <span class="op">}</span></span>
<span id="cb16-14"><a href="#cb16-14"></a><span class="op">}</span>;</span>
<span id="cb16-15"><a href="#cb16-15"></a></span>
<span id="cb16-16"><a href="#cb16-16"></a><span class="co">// if we did this as a class template to specialize</span></span>
<span id="cb16-17"><a href="#cb16-17"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span></span>
<span id="cb16-18"><a href="#cb16-18"></a><span class="kw">struct</span> N<span class="op">::</span>Eq<span class="op">&lt;</span>Widget<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb16-19"><a href="#cb16-19"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> eq<span class="op">(</span>Widget a, Widget b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-20"><a href="#cb16-20"></a>        <span class="cf">return</span> a<span class="op">.</span>i <span class="op">==</span> b<span class="op">.</span>i;</span>
<span id="cb16-21"><a href="#cb16-21"></a>    <span class="op">}</span></span>
<span id="cb16-22"><a href="#cb16-22"></a>    </span>
<span id="cb16-23"><a href="#cb16-23"></a>    <span class="co">// have no mechanism for providing a default</span></span>
<span id="cb16-24"><a href="#cb16-24"></a>    <span class="co">// so it&#39;s either this or have some base class</span></span>
<span id="cb16-25"><a href="#cb16-25"></a>    <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> ne<span class="op">(</span>Widget a, Widget b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb16-26"><a href="#cb16-26"></a>        <span class="cf">return</span> <span class="kw">not</span> eq<span class="op">(</span>a, b<span class="op">)</span>;</span>
<span id="cb16-27"><a href="#cb16-27"></a>    <span class="op">}</span></span>
<span id="cb16-28"><a href="#cb16-28"></a><span class="op">}</span>;</span></code></pre></div>
<p><code class="sourceCode cpp">tag_invoke</code> also doesn’t really help on the diagnostics front. For this example, I’m requiring that <code class="sourceCode cpp">eq</code> return specifically <code class="sourceCode cpp"><span class="dt">bool</span></code>. If I wanted to opt-in, and thus explicitly wrote a function named <code class="sourceCode cpp">tag_invoke</code>, but accidentally returned <code class="sourceCode cpp"><span class="dt">int</span></code>? This is what I get from gcc:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb17-1"><a href="#cb17-1"></a>&lt;source&gt;:64:18: error: static assertion failed</span>
<span id="cb17-2"><a href="#cb17-2"></a>   64 | static_assert(N::equality_comparable&lt;Widget&gt;);</span>
<span id="cb17-3"><a href="#cb17-3"></a>      |               ~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
<span id="cb17-4"><a href="#cb17-4"></a>&lt;source&gt;:64:18: note: constraints not satisfied</span>
<span id="cb17-5"><a href="#cb17-5"></a>&lt;source&gt;:53:13:   required by the constraints of &#39;template&lt;class T&gt; concept N::equality_comparable&#39;</span>
<span id="cb17-6"><a href="#cb17-6"></a>&lt;source&gt;:54:9:   in requirements with &#39;std::remove_reference_t&lt;_Tp&gt;&amp; t&#39; [with T = Widget]</span>
<span id="cb17-7"><a href="#cb17-7"></a>&lt;source&gt;:55:15: note: the required expression &#39;N::eq(t, t)&#39; is invalid, because</span>
<span id="cb17-8"><a href="#cb17-8"></a>   55 |             eq(t, t);</span>
<span id="cb17-9"><a href="#cb17-9"></a>      |             ~~^~~~~~</span>
<span id="cb17-10"><a href="#cb17-10"></a>&lt;source&gt;:55:15: error: no match for call to &#39;(const N::eq_fn) (std::remove_reference_t&lt;Widget&gt;&amp;, std::remove_reference_t&lt;Widget&gt;&amp;)&#39;</span>
<span id="cb17-11"><a href="#cb17-11"></a>&lt;source&gt;:28:24: note: candidate: &#39;template&lt;class T&gt;  requires  same_as&lt;typename std::invoke_result&lt;xstd::tag_invoke_fn, N::eq_fn, const T&amp;, const T&amp;&gt;::type, bool&gt; constexpr bool N::eq_fn::operator()(const T&amp;, const T&amp;) const&#39;</span>
<span id="cb17-12"><a href="#cb17-12"></a>   28 |         constexpr bool operator()(T const&amp; x, T const&amp; y) const {</span>
<span id="cb17-13"><a href="#cb17-13"></a>      |                        ^~~~~~~~</span>
<span id="cb17-14"><a href="#cb17-14"></a>&lt;source&gt;:28:24: note:   template argument deduction/substitution failed:</span>
<span id="cb17-15"><a href="#cb17-15"></a>&lt;source&gt;:28:24: note: constraints not satisfied</span>
<span id="cb17-16"><a href="#cb17-16"></a>In file included from &lt;source&gt;:1:</span>
<span id="cb17-17"><a href="#cb17-17"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/concepts: In substitution of &#39;template&lt;class T&gt;  requires  same_as&lt;typename std::invoke_result&lt;xstd::tag_invoke_fn, N::eq_fn, const T&amp;, const T&amp;&gt;::type, bool&gt; constexpr bool N::eq_fn::operator()(const T&amp;, const T&amp;) const [with T = Widget]&#39;:</span>
<span id="cb17-18"><a href="#cb17-18"></a>&lt;source&gt;:55:15:   required from here</span>
<span id="cb17-19"><a href="#cb17-19"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/concepts:57:15:   required for the satisfaction of &#39;__same_as&lt;_Tp, _Up&gt;&#39; [with _Tp = int; _Up = bool]</span>
<span id="cb17-20"><a href="#cb17-20"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/concepts:62:13:   required for the satisfaction of &#39;same_as&lt;typename std::invoke_result&lt;xstd::tag_invoke_fn, N::eq_fn, const T&amp;, const T&amp;&gt;::type, bool&gt;&#39; [with T = Widget]</span>
<span id="cb17-21"><a href="#cb17-21"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/concepts:57:32: note: the expression &#39;is_same_v&lt;_Tp, _Up&gt; [with _Tp = int; _Up = bool]&#39; evaluated to &#39;false&#39;</span>
<span id="cb17-22"><a href="#cb17-22"></a>   57 |       concept __same_as = std::is_same_v&lt;_Tp, _Up&gt;;</span>
<span id="cb17-23"><a href="#cb17-23"></a>      |                           ~~~~~^~~~~~~~~~~~~~~~~~~</span>
<span id="cb17-24"><a href="#cb17-24"></a>&lt;source&gt;:56:15: note: the required expression &#39;N::ne(t, t)&#39; is invalid, because</span>
<span id="cb17-25"><a href="#cb17-25"></a>   56 |             ne(t, t);</span>
<span id="cb17-26"><a href="#cb17-26"></a>      |             ~~^~~~~~</span>
<span id="cb17-27"><a href="#cb17-27"></a>&lt;source&gt;:56:15: error: no match for call to &#39;(const N::ne_fn) (std::remove_reference_t&lt;Widget&gt;&amp;, std::remove_reference_t&lt;Widget&gt;&amp;)&#39;</span>
<span id="cb17-28"><a href="#cb17-28"></a>&lt;source&gt;:45:24: note: candidate: &#39;template&lt;class T&gt;  requires  same_as&lt;typename std::invoke_result&lt;xstd::tag_invoke_fn, N::ne_fn, const T&amp;, const T&amp;&gt;::type, bool&gt; constexpr bool N::ne_fn::operator()(const T&amp;, const T&amp;) const&#39;</span>
<span id="cb17-29"><a href="#cb17-29"></a>   45 |         constexpr bool operator()(T const&amp; x, T const&amp; y) const {</span>
<span id="cb17-30"><a href="#cb17-30"></a>      |                        ^~~~~~~~</span>
<span id="cb17-31"><a href="#cb17-31"></a>&lt;source&gt;:45:24: note:   template argument deduction/substitution failed:</span>
<span id="cb17-32"><a href="#cb17-32"></a>&lt;source&gt;:45:24: note: constraints not satisfied</span>
<span id="cb17-33"><a href="#cb17-33"></a>&lt;source&gt;: In substitution of &#39;template&lt;class T&gt;  requires  same_as&lt;typename std::invoke_result&lt;xstd::tag_invoke_fn, N::ne_fn, const T&amp;, const T&amp;&gt;::type, bool&gt; constexpr bool N::ne_fn::operator()(const T&amp;, const T&amp;) const [with T = Widget]&#39;:</span>
<span id="cb17-34"><a href="#cb17-34"></a>&lt;source&gt;:56:15:   required from here</span>
<span id="cb17-35"><a href="#cb17-35"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/concepts:57:15:   required for the satisfaction of &#39;__same_as&lt;_Tp, _Up&gt;&#39; [with _Tp = typename std::invoke_result&lt;xstd::tag_invoke_fn, N::ne_fn, const T&amp;, const T&amp;&gt;::type; _Up = bool]</span>
<span id="cb17-36"><a href="#cb17-36"></a>/opt/compiler-explorer/gcc-trunk-20210102/include/c++/11.0.0/concepts:62:13:   required for the satisfaction of &#39;same_as&lt;typename std::invoke_result&lt;xstd::tag_invoke_fn, N::ne_fn, const T&amp;, const T&amp;&gt;::type, bool&gt;&#39; [with T = Widget]</span>
<span id="cb17-37"><a href="#cb17-37"></a>&lt;source&gt;:56:15: error: no type named &#39;type&#39; in &#39;struct std::invoke_result&lt;xstd::tag_invoke_fn, N::ne_fn, const Widget&amp;, const Widget&amp;&gt;&#39;</span>
<span id="cb17-38"><a href="#cb17-38"></a>   56 |             ne(t, t);</span>
<span id="cb17-39"><a href="#cb17-39"></a>      |             ~~^~~~~~</span></code></pre></div>
<p>There is <em>something</em> in the error message that says that <code class="sourceCode cpp"><span class="dt">int</span></code> isn’t the same type as <code class="sourceCode cpp"><span class="dt">bool</span></code>. But it’s not exactly easy to figure this out. Certainly as compared to a similar example involving virtual member functions:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb18-1"><a href="#cb18-1"></a>&lt;source&gt;:65:9: error: conflicting return type specified for &#39;virtual int Widget::eq() const&#39;</span>
<span id="cb18-2"><a href="#cb18-2"></a>   65 |     int eq() const override { return 0; }</span>
<span id="cb18-3"><a href="#cb18-3"></a>      |         ^~</span>
<span id="cb18-4"><a href="#cb18-4"></a>&lt;source&gt;:61:18: note: overridden function is &#39;virtual bool Eq::eq() const&#39;</span>
<span id="cb18-5"><a href="#cb18-5"></a>   61 |     virtual bool eq() const = 0;</span>
<span id="cb18-6"><a href="#cb18-6"></a>      |                  ^~</span></code></pre></div>
<p>Let’s add <code class="sourceCode cpp">tag_invoke</code> to the scoreboard:</p>
<table>
<thead>
<tr class="header">
<th>
</th>
<th>
<code class="sourceCode cpp"><span class="kw">virtual</span></code></br>member functions
</th>
<th>
class template<br />specialization
</th>
<th>
Pure<br />ADL
</th>
<th>
CPOs
</th>
<th>
<code class="sourceCode cpp">tag_invoke</code>
</th>
</tr>
</th>
<tbody>
<tr>
<td>
Interface visible in code
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
</tr>
<tr>
<td>
Providing default implementations
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Explicit opt-in
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Diagnose incorrect opt-in
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
</tr>
<tr>
<td>
Easily invoke the customization
</td>
<td>
✔️
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Verify implementation
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
</tr>
<tr>
<td>
Atomic grouping of functionality
</td>
<td>
✔️
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
</tr>
<tr>
<td>
Non-intrusive
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Associated Types
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
</tr>
</tbody>
</table>
<h2 data-number="2.5" id="better-enough"><span class="header-section-number">2.5</span> Better Enough?<a href="#better-enough" class="self-link"></a></h2>
<p>If <code class="sourceCode cpp">tag_invoke</code> is improving on CPOs (and it is, even when I measure by criteria that are not related to the problems the authors set out to solve), why do I claim, as I do in the the title of this paper, that we need a language solution to this problem?</p>
<p>Because this is how I would implement the <code class="sourceCode cpp">eq</code>/<code class="sourceCode cpp">ne</code> interface in Rust (wherein this is called <code class="sourceCode cpp">PartialEq</code>):</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">trait</span> <span class="bu">PartialEq</span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2"></a>    <span class="kw">fn</span> eq(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> rhs<span class="op">:</span> <span class="op">&amp;</span><span class="dt">Self</span>) <span class="op">-&gt;</span> <span class="dt">bool</span><span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3"></a>    </span>
<span id="cb1-4"><a href="#cb1-4"></a>    <span class="kw">fn</span> ne(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> rhs<span class="op">:</span> <span class="op">&amp;</span><span class="dt">Self</span>) <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5"></a>        <span class="op">!</span><span class="kw">self</span><span class="op">.</span>eq(rhs)</span>
<span id="cb1-6"><a href="#cb1-6"></a>    <span class="op">}</span></span>
<span id="cb1-7"><a href="#cb1-7"></a><span class="op">}</span></span></code></pre></div>
<p>This is 7 lines of code, even including the empty line and the two lines containing a single close brace. This trivial implementation, which you probably understand even if you don’t know Rust, <em>easily</em> meets all of the criteria presented thus far. And unlike CPOs and <code class="sourceCode cpp">tag_invoke</code>, where the extent of the ability to protect the user from faulty implementations or provide them with interface checks is dependent on the class author writing them correctly, here these checks are handled by and provided by the language. As a result, the checks are more robust, and the interface author doesn’t have to do anything.</p>
<p>Moreover, it even meets one of <code class="sourceCode cpp">tag_invoke</code>’s stated criteria: it does not globally reserve names. Though it does not meet the other: you cannot transparently implement and pass-through a trait that you do not know about.</p>
<p>Ultimately, I want us to aspire to more than replacing one set of library machinery that solves a subset of the problem with a different set of library machinery that solves a larger subset of the problem… where neither set of library machinery actually gives you insight into what the interface is to begin with.</p>
<p>To make this more clear:</p>
<table>
<thead>
<tr class="header">
<th>
</th>
<th>
<code class="sourceCode cpp"><span class="kw">virtual</span></code></br>member functions
</th>
<th>
class template<br />specialization
</th>
<th>
Pure<br />ADL
</th>
<th>
CPOs
</th>
<th>
<code class="sourceCode cpp">tag_invoke</code>
</th>
<th>
Rust<br />Traits
</th>
</tr>
</th>
<tbody>
<tr>
<td>
Interface visible in code
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Providing default implementations
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Explicit opt-in
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Diagnose incorrect opt-in
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Easily invoke the customization
</td>
<td>
✔️
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Verify implementation
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Atomic grouping of functionality
</td>
<td>
✔️
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Non-intrusive
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Associated Types
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
</tr>
</tbody>
</table>
<h2 data-number="2.6" id="the-swap-example"><span class="header-section-number">2.6</span> The swap example<a href="#the-swap-example" class="self-link"></a></h2>
<p>To help drive home the significance of the diagnostics and the fact that neither CPOs nor <code class="sourceCode cpp">tag_invoke</code> can possibly provide them, consider the following incorrect opt-in to <code class="sourceCode cpp">swap</code>:</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1"></a><span class="kw">namespace</span> N <span class="op">{</span></span>
<span id="cb19-2"><a href="#cb19-2"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb19-3"><a href="#cb19-3"></a>    <span class="kw">struct</span> Widget <span class="op">{</span> <span class="op">...</span> <span class="op">}</span>;</span>
<span id="cb19-4"><a href="#cb19-4"></a></span>
<span id="cb19-5"><a href="#cb19-5"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb19-6"><a href="#cb19-6"></a>    <span class="dt">void</span> swap<span class="op">(</span>Widget<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span>, Widget<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;)</span>;</span>
<span id="cb19-7"><a href="#cb19-7"></a><span class="op">}</span></span></code></pre></div>
<p>Regardless of if we’re using CPOs or <code class="sourceCode cpp">tag_invoke</code>, what we have here is an incorrect opt-in to <code class="sourceCode cpp">swap</code>. We need a function that takes two <code class="sourceCode cpp">T<span class="op">&amp;</span></code>s but we accidentally made one of them <code class="sourceCode cpp"><span class="kw">const</span></code>. This error is not diagnosable.</p>
<p>Why not? Both implementations basically detect the customization point by seeing if they can find a valid candidate for <code class="sourceCode cpp">swap<span class="op">(</span>x, x<span class="op">)</span></code> for a <code class="sourceCode cpp">T<span class="op">&amp;</span> x</code>. There’s no mechanism we have to detect the difference between a <code class="sourceCode cpp">swap</code> that exists and is wrong (like the above) and a <code class="sourceCode cpp">swap</code> that doesn’t exist. We just detect that <code class="sourceCode cpp">swap<span class="op">(</span>x, x<span class="op">)</span></code> is an invalid expression. The result is that we fall-back to using the default implementation of <code class="sourceCode cpp">swap</code>, and get no hint that we did something wrong! The only way we’d notice this if actually detected a slow-down of some kind, or were specifically testing the <code class="sourceCode cpp">swap</code> here very carefully.</p>
<p>A different kind of incorrect opt-in would be if we’d accidentally done this:</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb20-2"><a href="#cb20-2"></a><span class="dt">void</span> swap<span class="op">(</span>Widget<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span>, Widget<span class="op">&lt;</span>T<span class="op">&gt;)</span>;</span></code></pre></div>
<p>That is, take the second parameter by value instead of by lvalue-reference. Here, our candidate <em>would</em> get selected, but just not actually do a proper swap. We’d eventually discover this error by seeing <code class="sourceCode cpp">swap</code> fail to actually <code class="sourceCode cpp">swap</code> one of the arguments.</p>
<p>A third kind of incorrect opt-in would be if we put it in the wrong namespace:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1"></a><span class="kw">namespace</span> N <span class="op">{</span></span>
<span id="cb21-2"><a href="#cb21-2"></a>    <span class="kw">namespace</span> Inner <span class="op">{</span></span>
<span id="cb21-3"><a href="#cb21-3"></a>        <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb21-4"><a href="#cb21-4"></a>        <span class="kw">struct</span> Widget <span class="op">{</span> <span class="op">...</span> <span class="op">}</span>;</span>
<span id="cb21-5"><a href="#cb21-5"></a>    <span class="op">}</span></span>
<span id="cb21-6"><a href="#cb21-6"></a>    </span>
<span id="cb21-7"><a href="#cb21-7"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb21-8"><a href="#cb21-8"></a>    <span class="dt">void</span> swap<span class="op">(</span>Inner<span class="op">::</span>Widget<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span>, Inner<span class="op">::</span>Widget<span class="op">&lt;</span>T<span class="op">&gt;&amp;)</span>;</span>
<span id="cb21-9"><a href="#cb21-9"></a><span class="op">}</span></span></code></pre></div>
<p>Here, we finally got the parameters right. But ADL won’t find this overload, since <code class="sourceCode cpp">N</code> isn’t an associated namespace of <code class="sourceCode cpp">N<span class="op">::</span>Inner<span class="op">::</span>Widget<span class="op">&lt;</span>T<span class="op">&gt;</span></code>, only <code class="sourceCode cpp">N<span class="op">::</span>Inner</code> is.</p>
<p>The first problem is something that might be guarded against, perhaps by verifying that <code class="sourceCode cpp">swap<span class="op">(</span>c, c<span class="op">)</span></code> for a <code class="sourceCode cpp">T <span class="kw">const</span><span class="op">&amp;</span> c</code> does not find a candidate if <code class="sourceCode cpp">swap<span class="op">(</span>x, x<span class="op">)</span></code> did not, or some other similar implementation heroics. But this basically means doing an extra bout of overload resolution for every swap, even when <em>not</em> providing a custom swap is fairly typical, so seems unlikely to be done. I’m not sure how you could guard against either the second or third problems.</p>
<p>The problem here is we’re not just writing a function template whose name is <code class="sourceCode cpp">swap</code> - we’re very specifically opting into an interface. It’s just that unlike virtual member functions, we have no way of expressing this intent today. And without that intent, we can’t get diagnostics for such mistakes.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="relevant-work"><span class="header-section-number">3</span> Relevant Work<a href="#relevant-work" class="self-link"></a></h1>
<p>I don’t want to just point to Rust and ask that we keep up. I also want to highlight existing work in C++ specifically that can address this problem as well.</p>
<h2 data-number="3.1" id="customization-point-functions"><span class="header-section-number">3.1</span> Customization Point Functions<a href="#customization-point-functions" class="self-link"></a></h2>
<p>One paper that addresses this topic is Matt Calabrese’s <span class="citation" data-cites="P1292R0">[<a href="#ref-P1292R0" role="doc-biblioref">P1292R0</a>]</span>. This paper proposes a language facility that is a direct translation of C++ virtual member functions from the dynamic polymorphism realm into the static polymorphism realm. We can implement the recurring example in this paper with such a facility as follows:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1"></a><span class="kw">namespace</span> N <span class="op">{</span></span>
<span id="cb22-2"><a href="#cb22-2"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb22-3"><a href="#cb22-3"></a>    <span class="kw">virtual</span> <span class="kw">constexpr</span> <span class="kw">auto</span> eq<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span>, T <span class="kw">const</span><span class="op">&amp;)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">=</span> <span class="dv">0</span>;</span>
<span id="cb22-4"><a href="#cb22-4"></a>    </span>
<span id="cb22-5"><a href="#cb22-5"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb22-6"><a href="#cb22-6"></a>    <span class="kw">virtual</span> <span class="kw">constexpr</span> <span class="kw">auto</span> ne<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb22-7"><a href="#cb22-7"></a>        <span class="cf">return</span> <span class="kw">not</span> eq<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb22-8"><a href="#cb22-8"></a>    <span class="op">}</span></span>
<span id="cb22-9"><a href="#cb22-9"></a>    </span>
<span id="cb22-10"><a href="#cb22-10"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb22-11"><a href="#cb22-11"></a>    <span class="kw">concept</span> equality_comparable <span class="op">=</span></span>
<span id="cb22-12"><a href="#cb22-12"></a>        <span class="kw">requires</span> <span class="op">(</span>std<span class="op">::</span>remove_reference_t<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span> t<span class="op">)</span> <span class="op">{</span></span>
<span id="cb22-13"><a href="#cb22-13"></a>            eq<span class="op">(</span>t, t<span class="op">)</span>;</span>
<span id="cb22-14"><a href="#cb22-14"></a>            ne<span class="op">(</span>t, t<span class="op">)</span>;</span>
<span id="cb22-15"><a href="#cb22-15"></a>        <span class="op">}</span>;    </span>
<span id="cb22-16"><a href="#cb22-16"></a><span class="op">}</span></span></code></pre></div>
<p>Which is now just 16 lines of code.</p>
<p>We would opt-in to this facility by providing an <code class="sourceCode cpp"><span class="kw">override</span></code>:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1"></a><span class="kw">struct</span> Widget <span class="op">{</span></span>
<span id="cb23-2"><a href="#cb23-2"></a>    <span class="dt">int</span> i;</span>
<span id="cb23-3"><a href="#cb23-3"></a><span class="op">}</span>;</span>
<span id="cb23-4"><a href="#cb23-4"></a></span>
<span id="cb23-5"><a href="#cb23-5"></a><span class="kw">auto</span> eq<span class="op">(</span>Widget <span class="kw">const</span><span class="op">&amp;</span> x, Widget <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="kw">override</span> <span class="op">:</span> N<span class="op">::</span>eq <span class="op">{</span></span>
<span id="cb23-6"><a href="#cb23-6"></a>    <span class="cf">return</span> x<span class="op">.</span>i <span class="op">==</span> y<span class="op">.</span>i;</span>
<span id="cb23-7"><a href="#cb23-7"></a><span class="op">}</span></span></code></pre></div>
<p>This is a far, far simpler implementation for the library author, that is easier to understand for the reader, and does a lot more for us, since the language can do more checking for us. It’s definitely a big step between <code class="sourceCode cpp">tag_invoke</code> and Rust:</p>
<table>
<thead>
<tr class="header">
<th>
</th>
<th>
<code class="sourceCode cpp"><span class="kw">virtual</span></code></br>member functions
</th>
<th>
class template<br />specialization
</th>
<th>
Pure<br />ADL
</th>
<th>
CPOs
</th>
<th>
<code class="sourceCode cpp">tag_invoke</code>
</th>
<th>
customization<br />point functions
</th>
<th>
Rust<br />Traits
</th>
</tr>
</th>
<tbody>
<tr>
<td>
Interface visible in code
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Providing default implementations
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Explicit opt-in
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Diagnose incorrect opt-in
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Easily invoke the customization
</td>
<td>
✔️
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Verify implementation
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Atomic grouping of functionality
</td>
<td>
✔️
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Non-intrusive
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Associated Types
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
</tr>
</tbody>
</table>
<p>While customization point functions have several clear benefits, they still don’t address all the issues here. In particular, when dealing with an interface that logically has multiple customization points, there’s no way of aggregating them together (short of providing a concept that has to unify them), and so there’s nothing to prevent a user from doing something like providing an override for <code class="sourceCode cpp">ne</code> but not for <code class="sourceCode cpp">eq</code>.</p>
<p>And customization point functions are limited to the kinds of things that functions can do, so they likewise don’t provide any added benefit where associated types are concerned as compared to CPOs or <code class="sourceCode cpp">tag_invoke</code>. They still require type traits for everything interesting.</p>
<p>What customization point functions <em>do</em> provide is an ability to potentially address the other issue <code class="sourceCode cpp">tag_invoke</code> sought to solve: the ability to forward customizations. With P1292, we already have a dissociation between the <em>name</em> of the override and the <em>name</em> of the function that it is overriding. The paper provides the following example:</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> It, <span class="kw">class</span> Distance<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-2"></a><span class="kw">virtual</span> <span class="kw">constexpr</span> <span class="dt">void</span> advance<span class="op">(</span>It<span class="op">&amp;</span> it, Distance n<span class="op">)</span></span>
<span id="cb24-3"><a href="#cb24-3"></a>    <span class="kw">requires</span> InputIterator<span class="op">&lt;</span>It<span class="op">&gt;</span></span>
<span id="cb24-4"><a href="#cb24-4"></a><span class="op">{</span></span>
<span id="cb24-5"><a href="#cb24-5"></a>    <span class="cf">for</span> <span class="op">(</span>; n <span class="op">!=</span> <span class="dv">0</span>; <span class="op">--</span>n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-6"><a href="#cb24-6"></a>        <span class="op">++</span>it;</span>
<span id="cb24-7"><a href="#cb24-7"></a>    <span class="op">}</span></span>
<span id="cb24-8"><a href="#cb24-8"></a><span class="op">}</span></span>
<span id="cb24-9"><a href="#cb24-9"></a></span>
<span id="cb24-10"><a href="#cb24-10"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> It, <span class="kw">class</span> Distance<span class="op">&gt;</span></span>
<span id="cb24-11"><a href="#cb24-11"></a><span class="kw">constexpr</span> <span class="dt">void</span> advance_bidirectional<span class="op">(</span>It<span class="op">&amp;</span> it, Distance n<span class="op">)</span> <span class="kw">override</span></span>
<span id="cb24-12"><a href="#cb24-12"></a>  <span class="kw">requires</span> BidirectionalIterator<span class="op">&lt;</span>It<span class="op">&gt;</span></span>
<span id="cb24-13"><a href="#cb24-13"></a>  <span class="op">:</span> advance</span>
<span id="cb24-14"><a href="#cb24-14"></a><span class="op">{</span></span>
<span id="cb24-15"><a href="#cb24-15"></a>    <span class="cf">if</span> <span class="op">(</span>n <span class="op">&gt;=</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-16"><a href="#cb24-16"></a>        <span class="cf">for</span> <span class="op">(</span>; n <span class="op">!=</span> <span class="dv">0</span>; <span class="op">--</span>n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-17"><a href="#cb24-17"></a>            <span class="op">++</span>it;</span>
<span id="cb24-18"><a href="#cb24-18"></a>        <span class="op">}</span></span>
<span id="cb24-19"><a href="#cb24-19"></a>    <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb24-20"><a href="#cb24-20"></a>        <span class="cf">for</span><span class="op">(</span>; n <span class="op">!=</span> <span class="dv">0</span>; <span class="op">++</span>n<span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-21"><a href="#cb24-21"></a>            <span class="op">--</span>it;</span>
<span id="cb24-22"><a href="#cb24-22"></a>        <span class="op">}</span></span>
<span id="cb24-23"><a href="#cb24-23"></a>    <span class="op">}</span></span>
<span id="cb24-24"><a href="#cb24-24"></a><span class="op">}</span></span></code></pre></div>
<p>Lewis Baker (one of the <code class="sourceCode cpp">tag_invoke</code> authors) suggests an extension to this direction that allows deducing the the customization point being overriden. As in (the following example is reduced somewhat from a similar one in <span class="citation" data-cites="P2175R0">[<a href="#ref-P2175R0" role="doc-biblioref">P2175R0</a>]</span>, and takes the liberty of assuming we can implement customization point functions as members — an idea which does not appear in Matt’s paper at all):</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Receiver<span class="op">&gt;</span></span>
<span id="cb25-2"><a href="#cb25-2"></a><span class="kw">struct</span> receiver <span class="op">{</span></span>
<span id="cb25-3"><a href="#cb25-3"></a>    Receiver inner;</span>
<span id="cb25-4"><a href="#cb25-4"></a>    </span>
<span id="cb25-5"><a href="#cb25-5"></a>    <span class="co">// Override get_stop_token()</span></span>
<span id="cb25-6"><a href="#cb25-6"></a>    <span class="kw">auto</span> get_stop_token<span class="op">()</span> <span class="kw">const</span> <span class="op">-&gt;</span> std<span class="op">::</span>never_stop_token</span>
<span id="cb25-7"><a href="#cb25-7"></a>            <span class="kw">override</span> <span class="op">:</span> std<span class="op">::</span>execution<span class="op">::</span>get_stop_token</span>
<span id="cb25-8"><a href="#cb25-8"></a>    <span class="op">{</span></span>
<span id="cb25-9"><a href="#cb25-9"></a>        <span class="cf">return</span> <span class="op">{}</span></span>
<span id="cb25-10"><a href="#cb25-10"></a>    <span class="op">}</span></span>
<span id="cb25-11"><a href="#cb25-11"></a>    </span>
<span id="cb25-12"><a href="#cb25-12"></a>    <span class="co">// Pass through other customization points</span></span>
<span id="cb25-13"><a href="#cb25-13"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">auto</span> CPO, <span class="kw">typename</span> Self, <span class="kw">typename</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb25-14"><a href="#cb25-14"></a>    <span class="kw">auto</span> fwd_cpo<span class="op">(</span><span class="kw">this</span> Self<span class="op">&amp;&amp;</span> self, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span>CPO<span class="op">(</span>FWD<span class="op">(</span>self<span class="op">).</span>inner, FWD<span class="op">(</span>args<span class="op">)...))</span></span>
<span id="cb25-15"><a href="#cb25-15"></a>            <span class="kw">override</span><span class="op">:</span> CPO</span>
<span id="cb25-16"><a href="#cb25-16"></a>    <span class="op">{</span></span>
<span id="cb25-17"><a href="#cb25-17"></a>        <span class="cf">return</span> CPO<span class="op">(</span>FWD<span class="op">(</span>self<span class="op">).</span>inner, FWD<span class="op">(</span>args<span class="op">)...)</span>;</span>
<span id="cb25-18"><a href="#cb25-18"></a>    <span class="op">}</span></span>
<span id="cb25-19"><a href="#cb25-19"></a><span class="op">}</span>;</span></code></pre></div>
<p>Definitely something to seriously consider. One issue might be how to figure out how to pick the right overrides. But collecting overrides and relying on them to be constrained seems likely to produce a smaller set of candidates than having to perform name lookup across all associated namespaces and classes.</p>
<h2 data-number="3.2" id="reflective-metaprogramming"><span class="header-section-number">3.2</span> Reflective Metaprogramming<a href="#reflective-metaprogramming" class="self-link"></a></h2>
<p>I’ve pointed out a few times the relative sizes of the solutions presented thus far: that the CPO solution requires 42 lines of code and the <code class="sourceCode cpp">tag_invoke</code> solution requires 36, customization point functions allow us to reduce this to 16, while the Rust traits example only requires 7. One follow-up question to this is: to what extent can reflective (generative) metaprogramming address this need?</p>
<p>Consider a block of code like the following (I’m using the stereotypes suggested in <span class="citation" data-cites="P2237R0">[<a href="#ref-P2237R0" role="doc-biblioref">P2237R0</a>]</span>. The particular syntax chosen here might be incorrect, but probably isn’t relevant to the point I’m trying to make):</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1"></a><span class="kw">namespace</span> N <span class="op">{</span></span>
<span id="cb26-2"><a href="#cb26-2"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb26-3"><a href="#cb26-3"></a>    <span class="op">&lt;&lt;</span>virtual_<span class="op">&gt;&gt;</span> <span class="kw">constexpr</span> <span class="kw">auto</span> eq<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span>, T <span class="kw">const</span><span class="op">&amp;)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb26-4"><a href="#cb26-4"></a>    </span>
<span id="cb26-5"><a href="#cb26-5"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb26-6"><a href="#cb26-6"></a>        <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">){</span></span>
<span id="cb26-7"><a href="#cb26-7"></a>            eq<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb26-8"><a href="#cb26-8"></a>        <span class="op">}</span></span>
<span id="cb26-9"><a href="#cb26-9"></a>    <span class="op">&lt;&lt;</span>virtual_<span class="op">&gt;&gt;</span> <span class="kw">constexpr</span> <span class="kw">auto</span> ne<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb26-10"><a href="#cb26-10"></a>        <span class="cf">return</span> <span class="kw">not</span> eq<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb26-11"><a href="#cb26-11"></a>    <span class="op">}</span></span>
<span id="cb26-12"><a href="#cb26-12"></a><span class="op">}</span></span></code></pre></div>
<p>This looks quite a bit like the customization point function implementation, right? Let’s see what we could do with such a thing. We could implement <code class="sourceCode cpp">virtual_</code> to produce class templates that look like this:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1"></a><span class="kw">namespace</span> N<span class="op">::</span>virtual_ <span class="op">{</span></span>
<span id="cb27-2"><a href="#cb27-2"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb27-3"><a href="#cb27-3"></a>    <span class="kw">struct</span> eq_t;</span>
<span id="cb27-4"><a href="#cb27-4"></a></span>
<span id="cb27-5"><a href="#cb27-5"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb27-6"><a href="#cb27-6"></a>    <span class="kw">using</span> eq_parameters <span class="op">=</span> mp_list<span class="op">&lt;</span>T <span class="kw">const</span><span class="op">&amp;</span>, T <span class="kw">const</span><span class="op">&amp;&gt;</span>;</span>
<span id="cb27-7"><a href="#cb27-7"></a>    </span>
<span id="cb27-8"><a href="#cb27-8"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb27-9"><a href="#cb27-9"></a>    <span class="kw">concept</span> eq_return <span class="op">=</span> std<span class="op">::</span>same_as<span class="op">&lt;</span>T, <span class="dt">bool</span><span class="op">&gt;</span>;</span>
<span id="cb27-10"><a href="#cb27-10"></a><span class="op">}</span></span>
<span id="cb27-11"><a href="#cb27-11"></a></span>
<span id="cb27-12"><a href="#cb27-12"></a><span class="kw">namespace</span> N <span class="op">{</span>    </span>
<span id="cb27-13"><a href="#cb27-13"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> eq <span class="op">=</span></span>
<span id="cb27-14"><a href="#cb27-14"></a>        <span class="op">[]&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb27-15"><a href="#cb27-15"></a>            <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">(</span>virtual_<span class="op">::</span>eq_t<span class="op">&lt;</span>T<span class="op">&gt;</span> f, T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb27-16"><a href="#cb27-16"></a>                <span class="op">{</span> f<span class="op">(</span>x, y<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> virtual_<span class="op">::</span>eq_return;</span>
<span id="cb27-17"><a href="#cb27-17"></a>            <span class="op">}</span></span>
<span id="cb27-18"><a href="#cb27-18"></a>        <span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb27-19"><a href="#cb27-19"></a>            <span class="cf">return</span> virtual_<span class="op">::</span>eq_t<span class="op">&lt;</span>T<span class="op">&gt;{}(</span>x, y<span class="op">)</span>;</span>
<span id="cb27-20"><a href="#cb27-20"></a>        <span class="op">}</span>;</span>
<span id="cb27-21"><a href="#cb27-21"></a><span class="op">}</span></span>
<span id="cb27-22"><a href="#cb27-22"></a></span>
<span id="cb27-23"><a href="#cb27-23"></a><span class="kw">namespace</span> N<span class="op">::</span>virtual_ <span class="op">{</span>    </span>
<span id="cb27-24"><a href="#cb27-24"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb27-25"><a href="#cb27-25"></a>    <span class="kw">struct</span> ne_t;</span>
<span id="cb27-26"><a href="#cb27-26"></a>    </span>
<span id="cb27-27"><a href="#cb27-27"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb27-28"><a href="#cb27-28"></a>        <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">){</span></span>
<span id="cb27-29"><a href="#cb27-29"></a>            eq<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb27-30"><a href="#cb27-30"></a>        <span class="op">}</span></span>
<span id="cb27-31"><a href="#cb27-31"></a>    <span class="kw">struct</span> ne_t<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb27-32"><a href="#cb27-32"></a>        <span class="kw">constexpr</span> <span class="kw">auto</span> <span class="kw">operator</span><span class="op">()(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb27-33"><a href="#cb27-33"></a>            <span class="cf">return</span> <span class="kw">not</span> eq<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb27-34"><a href="#cb27-34"></a>        <span class="op">}</span></span>
<span id="cb27-35"><a href="#cb27-35"></a>    <span class="op">}</span>;</span>
<span id="cb27-36"><a href="#cb27-36"></a>    </span>
<span id="cb27-37"><a href="#cb27-37"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb27-38"><a href="#cb27-38"></a>    <span class="kw">using</span> ne_parameters <span class="op">=</span> mp_list<span class="op">&lt;</span>T <span class="kw">const</span><span class="op">&amp;</span>, T <span class="kw">const</span><span class="op">&amp;&gt;</span>;    </span>
<span id="cb27-39"><a href="#cb27-39"></a>    </span>
<span id="cb27-40"><a href="#cb27-40"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb27-41"><a href="#cb27-41"></a>    <span class="kw">concept</span> ne_return <span class="op">=</span> std<span class="op">::</span>same_as<span class="op">&lt;</span>T, <span class="dt">bool</span><span class="op">&gt;</span>;    </span>
<span id="cb27-42"><a href="#cb27-42"></a><span class="op">}</span></span>
<span id="cb27-43"><a href="#cb27-43"></a></span>
<span id="cb27-44"><a href="#cb27-44"></a><span class="kw">namespace</span> N <span class="op">{</span>   </span>
<span id="cb27-45"><a href="#cb27-45"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> ne <span class="op">=</span></span>
<span id="cb27-46"><a href="#cb27-46"></a>        <span class="op">[]&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb27-47"><a href="#cb27-47"></a>            <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">(</span>virtual_<span class="op">::</span>ne_t<span class="op">&lt;</span>T<span class="op">&gt;</span> f, T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb27-48"><a href="#cb27-48"></a>                <span class="op">{</span> f<span class="op">(</span>x, y<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> virtual_<span class="op">::</span>ne_return;</span>
<span id="cb27-49"><a href="#cb27-49"></a>            <span class="op">}</span></span>
<span id="cb27-50"><a href="#cb27-50"></a>        <span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb27-51"><a href="#cb27-51"></a>            <span class="cf">return</span> virtual_<span class="op">::</span>ne_t<span class="op">&lt;</span>T<span class="op">&gt;{}(</span>x, y<span class="op">)</span>;</span>
<span id="cb27-52"><a href="#cb27-52"></a>        <span class="op">}</span>;   </span>
<span id="cb27-53"><a href="#cb27-53"></a><span class="op">}</span></span></code></pre></div>
<p>The algorithm here would be that for each function template <code class="sourceCode cpp">F</code> annotated by <code class="sourceCode cpp"><span class="op">&lt;&lt;</span>virtual_<span class="op">&gt;&gt;</span></code>:</p>
<ol type="1">
<li><p>Introduce a class template <code class="sourceCode cpp">F_t</code> into <code class="sourceCode cpp">N<span class="op">::</span>virtual_</code> with the same template parameters as <code class="sourceCode cpp">F</code>. If <code class="sourceCode cpp">F</code> has no definition, the class template has no definition (as in <code class="sourceCode cpp">eq</code>). If <code class="sourceCode cpp">F</code> has a definition, then copy it as the call operator. If <code class="sourceCode cpp">F</code> has a definition with constraints (as in <code class="sourceCode cpp">ne</code>), then introduce an empty primary class template and additionally add a constrained specialization, copying the constraints.</p></li>
<li><p>Introduce an alias template that stashes the types of the parameters in <code class="sourceCode cpp">F</code> for a given instantiation. This is probably not the right way to do this, but we do need to store <em>some</em> metadata somewhere about what the parameters need to be for this function in a way to allow us to verify them later. We also introduce a concept for the return type. If <code class="sourceCode cpp">F</code> returns a type <code class="sourceCode cpp">T</code> that is not <code class="sourceCode cpp"><span class="dt">void</span></code>, then that concept is <code class="sourceCode cpp">same_as<span class="op">&lt;</span>T<span class="op">&gt;</span></code>. If <code class="sourceCode cpp">F</code> returns <code class="sourceCode cpp">C <span class="kw">auto</span></code>, then that constraint is <code class="sourceCode cpp">C</code>. Otherwise, the constraint is just <code class="sourceCode cpp"><span class="kw">true</span></code>.</p></li>
<li><p>Introduce a lambda into <code class="sourceCode cpp">N</code> that is a transformed version of <code class="sourceCode cpp">F</code> that invokes <code class="sourceCode cpp">N<span class="op">::</span>virtual_<span class="op">::</span>F_t</code> when that is a valid expression whose return type satisfies <code class="sourceCode cpp">N<span class="op">::</span>virtual_<span class="op">::</span>F_return</code>.</p></li>
</ol>
<p>Rather than doing CPOs or <code class="sourceCode cpp">tag_invoke</code>, I’m actually going back to class template specialization here. But I’m trying to use reflection to hide all the problems with it, but keep its benefits (notably, a much smaller lookup space). But if the class template is hidden, how would you opt-in? We continue the stereotype approach and provide <code class="sourceCode cpp"><span class="kw">override</span></code> stereotype akin to the <code class="sourceCode cpp"><span class="kw">override</span></code> facility presented in the customization point functions paper.</p>
<p>As in:</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1"></a><span class="kw">namespace</span> N <span class="op">{</span></span>
<span id="cb28-2"><a href="#cb28-2"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span> <span class="kw">struct</span> Widget <span class="op">{</span> <span class="op">...</span> <span class="op">}</span>;</span>
<span id="cb28-3"><a href="#cb28-3"></a>    </span>
<span id="cb28-4"><a href="#cb28-4"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb28-5"><a href="#cb28-5"></a>    <span class="op">&lt;&lt;</span><span class="kw">override</span><span class="op">(</span>std<span class="op">::</span>ranges<span class="op">::</span>swap<span class="op">)&gt;&gt;</span> <span class="dt">void</span> swap<span class="op">(</span>Widget<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span> x, Widget<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
<span id="cb28-6"><a href="#cb28-6"></a><span class="op">}</span></span></code></pre></div>
<p>Such a stereotype could do all of the following:</p>
<ol type="1">
<li><p>Verify that <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>swap</code> is indeed a <code class="sourceCode cpp">virtual_</code> customization point. It is not at the moment (and this could be diagnosed at the point of declaration here), but let’s pretend it is for the sake of argument.</p></li>
<li><p>Verify that this implementation matches the interface of the <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>swap</code> customization point, by directly examining the function parameters and the return type this would let us reject the bad opt-in of <code class="sourceCode cpp">swap</code> at its point of declaration — for any of the incorrect opt-ins to swap presented <a href="#the-swap-example">earlier</a>. In this case (based on my guess implementation earlier), the parameters of swap would be <code class="sourceCode cpp">mp_list<span class="op">&lt;</span>T<span class="op">&amp;</span>, T<span class="op">&amp;&gt;</span></code>, so we should be able to reject the list <code class="sourceCode cpp">mp_list<span class="op">&lt;</span>Widget<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span>, Widget<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;&gt;</span></code> as being incompatible. Alternatively, we store the whole function signature and verify that it’s more specialized than the original. I may not be 100% sure what the right way to check this might be, but it at least seems to be that it’s <em>possible</em> to implement <code class="sourceCode cpp">virtual_</code> and <code class="sourceCode cpp"><span class="kw">override</span></code> such that we <em>could</em> check this.</p></li>
<li><p>Once we do both of those verifications, rewrite the provided definition to be a function template specialization (which is more difficult because we both have to figure out how to perform the specialization and would need to allow ourselves to specialize class templates in a different namespace that doesn’t change lookup context?):</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb29-2"><a href="#cb29-2"></a><span class="kw">struct</span> <span class="op">::</span>std<span class="op">::</span>ranges<span class="op">::</span>virtual_<span class="op">::</span>swap_t<span class="op">&lt;</span>Widget<span class="op">&lt;</span>T<span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb29-3"><a href="#cb29-3"></a>    <span class="dt">void</span> <span class="kw">operator</span><span class="op">()(</span>Widget<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span> x, Widget<span class="op">&lt;</span>T<span class="op">&gt;&amp;</span> y<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</span></span>
<span id="cb29-4"><a href="#cb29-4"></a><span class="op">}</span>;</span></code></pre></div></li>
</ol>
<p>Which should allow a library implementation to now accurately diagnose incorrect opt-ins, while providing an explicit opt-in syntax very similar to <span class="citation" data-cites="P1292R0">[<a href="#ref-P1292R0" role="doc-biblioref">P1292R0</a>]</span>.</p>
<p>Arguably the constraints that I illustrated earlier on the function objects aren’t actually necessary. That is, I showed <code class="sourceCode cpp">eq</code> as:</p>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1"></a><span class="kw">namespace</span> N <span class="op">{</span>    </span>
<span id="cb30-2"><a href="#cb30-2"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> eq <span class="op">=</span></span>
<span id="cb30-3"><a href="#cb30-3"></a>        <span class="op">[]&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb30-4"><a href="#cb30-4"></a>            <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">(</span>virtual_<span class="op">::</span>eq_t<span class="op">&lt;</span>T<span class="op">&gt;</span> f, T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb30-5"><a href="#cb30-5"></a>                <span class="op">{</span> f<span class="op">(</span>x, y<span class="op">)</span> <span class="op">}</span> <span class="op">-&gt;</span> virtual_<span class="op">::</span>eq_return;</span>
<span id="cb30-6"><a href="#cb30-6"></a>            <span class="op">}</span></span>
<span id="cb30-7"><a href="#cb30-7"></a>        <span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb30-8"><a href="#cb30-8"></a>            <span class="cf">return</span> virtual_<span class="op">::</span>eq_t<span class="op">&lt;</span>T<span class="op">&gt;{}(</span>x, y<span class="op">)</span>;</span>
<span id="cb30-9"><a href="#cb30-9"></a>        <span class="op">}</span>;</span>
<span id="cb30-10"><a href="#cb30-10"></a><span class="op">}</span></span></code></pre></div>
<p>We don’t need to verify the expression <code class="sourceCode cpp">f<span class="op">(</span>x, y<span class="op">)</span></code>. The <code class="sourceCode cpp"><span class="kw">override</span></code> stereotype already does that for us. We just need to validate that <code class="sourceCode cpp">virtual_<span class="op">::</span>eq_t<span class="op">&lt;</span>T<span class="op">&gt;</span></code> is a valid type, which should reduce some compile overhead:</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1"></a><span class="kw">namespace</span> N <span class="op">{</span>    </span>
<span id="cb31-2"><a href="#cb31-2"></a>    <span class="kw">inline</span> <span class="kw">constexpr</span> <span class="kw">auto</span> eq <span class="op">=</span></span>
<span id="cb31-3"><a href="#cb31-3"></a>        <span class="op">[]&lt;</span><span class="kw">typename</span> T<span class="op">&gt;</span></span>
<span id="cb31-4"><a href="#cb31-4"></a>            <span class="kw">requires</span> <span class="kw">requires</span> <span class="op">{</span></span>
<span id="cb31-5"><a href="#cb31-5"></a>                virtual_<span class="op">::</span>eq_t<span class="op">&lt;</span>T<span class="op">&gt;{}</span>;</span>
<span id="cb31-6"><a href="#cb31-6"></a>            <span class="op">}</span></span>
<span id="cb31-7"><a href="#cb31-7"></a>        <span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb31-8"><a href="#cb31-8"></a>            <span class="cf">return</span> virtual_<span class="op">::</span>eq_t<span class="op">&lt;</span>T<span class="op">&gt;{}(</span>x, y<span class="op">)</span>;</span>
<span id="cb31-9"><a href="#cb31-9"></a>        <span class="op">}</span>;</span>
<span id="cb31-10"><a href="#cb31-10"></a><span class="op">}</span></span></code></pre></div>
<p>The above requires a lot of new language features, but if what I’m describing here is actually implementable (and there are certainly <em>many</em> questions here about that), then we may be able to implement customization point functions exactly as a library. With all of their benefits (as compared to <code class="sourceCode cpp">tag_invoke</code>: having the implementation visible in code and the ability to diagnose incorrect opt-ins) and their weaknesses (no way of grouping multiple customization points into a cohesive unit, providing an easy verification for that grouping, or support for associated types).</p>
<p>I also haven’t the slighest idea how to do forwarding of arbitrary customization points in this model.</p>
<p>An important downside to this approach as compared to the customization point functions language feature is prvalue propagation. With <code class="sourceCode cpp"><span class="kw">virtual</span></code> member functions and the <code class="sourceCode cpp"><span class="kw">virtual</span></code> “free” functions design, if I have a <code class="sourceCode cpp"><span class="kw">virtual</span></code> function that takes a prvalue, invoking the customization point <em>directly</em> invokes the most derived implementation with a prvalue. That is, the prvalue is materialized at its target. The same is true of “pure” ADL-based customization points, since we just invoke the target function.</p>
<p>But this is not the case with CPOs, <code class="sourceCode cpp">tag_invoke</code>, or the above reflection-based implementation of class template specializations. In each of these cases, we invoke a function object that dispatches to the most derived implementation. This means the prvalue must be materialized earlier and then moved. This is a known gotcha with implementing something like <code class="sourceCode cpp">std<span class="op">::</span>function<span class="op">&lt;</span><span class="dt">void</span><span class="op">(</span>std<span class="op">::</span>string<span class="op">)&gt;</span></code> — it can’t quite be as good as you’d want it to be, because you end up with <em>two</em> functions in your call chain taking a <code class="sourceCode cpp">std<span class="op">::</span>string</code> (or, if you implement it poorly, more than two).</p>
<p>Perhaps there’s yet another language feature that could facilitate efficient prvalue materialization here? Expression aliases? Lazy parameters?</p>
<h2 data-number="3.3" id="c0x-concepts"><span class="header-section-number">3.3</span> C++0x Concepts<a href="#c0x-concepts" class="self-link"></a></h2>
<p>Rust is hardly the only language that can solve this problem. Indeed, C++0x Concepts <span class="citation" data-cites="N1758">[<a href="#ref-N1758" role="doc-biblioref">N1758</a>]</span> gave us a solution that is nearly identical to the Rust one (this appears in the paper under the name <code class="sourceCode cpp">EqualityComparable</code>, I’m just changing it to match the names used throughout the paper):</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Rust</strong>
</div></th>
<th><div style="text-align:center">
<strong>C++0x</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb2"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">trait</span> <span class="bu">PartialEq</span> <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2"></a>    <span class="kw">fn</span> eq(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> rhs<span class="op">:</span> <span class="op">&amp;</span><span class="dt">Self</span>) <span class="op">-&gt;</span> <span class="dt">bool</span><span class="op">;</span></span>
<span id="cb2-3"><a href="#cb2-3"></a>    </span>
<span id="cb2-4"><a href="#cb2-4"></a>    <span class="kw">fn</span> ne(<span class="op">&amp;</span><span class="kw">self</span><span class="op">,</span> rhs<span class="op">:</span> <span class="op">&amp;</span><span class="dt">Self</span>) <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-5"></a>        <span class="op">!</span><span class="kw">self</span><span class="op">.</span>eq(rhs)</span>
<span id="cb2-6"><a href="#cb2-6"></a>    <span class="op">}</span></span>
<span id="cb2-7"><a href="#cb2-7"></a><span class="op">}</span></span></code></pre></div></td>
<td><div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typeid</span> T<span class="op">&gt;</span></span>
<span id="cb32-2"><a href="#cb32-2"></a><span class="kw">concept</span> PartialEq <span class="op">{</span></span>
<span id="cb32-3"><a href="#cb32-3"></a>    <span class="kw">auto</span> eq<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span>, T <span class="kw">const</span><span class="op">&amp;)</span> <span class="op">-&gt;</span> <span class="dt">bool</span>;</span>
<span id="cb32-4"><a href="#cb32-4"></a>    </span>
<span id="cb32-5"><a href="#cb32-5"></a>    <span class="kw">auto</span> ne<span class="op">(</span>T <span class="kw">const</span><span class="op">&amp;</span> x, T <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb32-6"><a href="#cb32-6"></a>        <span class="cf">return</span> <span class="kw">not</span> eq<span class="op">(</span>x, y<span class="op">)</span>;</span>
<span id="cb32-7"><a href="#cb32-7"></a>    <span class="op">}</span></span>
<span id="cb32-8"><a href="#cb32-8"></a><span class="op">}</span>;</span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>The differences here are completely aesthetic; this solution performs just as well as the Rust one. Were I to be consistent with the other examples and stash this in <code class="sourceCode cpp"><span class="kw">namespace</span> N</code>, this would be just 10 lines of code (compared to 16 with customization point functions, 36 with <code class="sourceCode cpp">tag_invoke</code>, and 42 with customization point objects).</p>
<table>
<thead>
<tr class="header">
<th>
</th>
<th>
<code class="sourceCode cpp"><span class="kw">virtual</span></code></br>member functions
</th>
<th>
class template<br />specialization
</th>
<th>
Pure<br />ADL
</th>
<th>
CPOs
</th>
<th>
<code class="sourceCode cpp">tag_invoke</code>
</th>
<th>
customization<br />point functions
</th>
<th>
Rust<br />Traits
</th>
<th>
C++0x<br />Concepts
</th>
</tr>
</th>
<tbody>
<tr>
<td>
Interface visible in code
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Providing default implementations
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Explicit opt-in
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Diagnose incorrect opt-in
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Easily invoke the customization
</td>
<td>
✔️
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Verify implementation
</td>
<td>
✔️
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Atomic grouping of functionality
</td>
<td>
✔️
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Non-intrusive
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Associated Types
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
❌
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
</tbody>
</table>
<p>What we saw in each example so far - with customization point objects, with <code class="sourceCode cpp">tag_invoke</code>, and with customization point functions - was that we have to take these independent customization points and group them into <code class="sourceCode cpp"><span class="kw">concept</span></code> into order to indicate that they are closely related.</p>
<p>What C++0x Concepts showed us was that we could simply start from the grouped collection of customization points instead. But the opt-in mechanism for C++0x concepts was a little different: we have concept maps (see <span class="citation" data-cites="N2042">[<a href="#ref-N2042" role="doc-biblioref">N2042</a>]</span>). The <code class="sourceCode cpp">Widget</code> opt-in from earlier would be:</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1"></a><span class="kw">struct</span> Widget <span class="op">{</span> <span class="dt">int</span> i; <span class="op">}</span>;</span>
<span id="cb33-2"><a href="#cb33-2"></a></span>
<span id="cb33-3"><a href="#cb33-3"></a><span class="kw">template</span> <span class="op">&lt;&gt;</span></span>
<span id="cb33-4"><a href="#cb33-4"></a>concept_map PartialEq<span class="op">&lt;</span>Widget<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb33-5"><a href="#cb33-5"></a>    <span class="kw">auto</span> eq<span class="op">(</span>Widget <span class="kw">const</span><span class="op">&amp;</span> x, Widget <span class="kw">const</span><span class="op">&amp;</span> y<span class="op">)</span> <span class="op">-&gt;</span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb33-6"><a href="#cb33-6"></a>        <span class="cf">return</span> x<span class="op">.</span>i <span class="op">==</span> y<span class="op">.</span>i;</span>
<span id="cb33-7"><a href="#cb33-7"></a>    <span class="op">}</span></span>
<span id="cb33-8"><a href="#cb33-8"></a><span class="op">}</span>;</span></code></pre></div>
<p>The invocation model is quite different too. Using customization point functions, <code class="sourceCode cpp">N<span class="op">::</span>eq</code> is just a function that I can invoke wherever. Indeed it also behaves as an object, so I can pass it as an algorithm to a different algorithm (e.g. <code class="sourceCode cpp">views<span class="op">::</span>group_by<span class="op">(</span>N<span class="op">::</span>eq<span class="op">)</span></code> is perfectly valid). But C++0x Concepts didn’t have this idea that <code class="sourceCode cpp">PartialEq<span class="op">::</span>eq</code> would be any kind of callable. Which makes it entirely non-obvious to figure out how to forward a customization point.</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Receiver<span class="op">&gt;</span></span>
<span id="cb34-2"><a href="#cb34-2"></a><span class="kw">struct</span> receiver <span class="op">{</span></span>
<span id="cb34-3"><a href="#cb34-3"></a>    Receiver inner;</span>
<span id="cb34-4"><a href="#cb34-4"></a><span class="op">}</span>;</span>
<span id="cb34-5"><a href="#cb34-5"></a></span>
<span id="cb34-6"><a href="#cb34-6"></a><span class="co">// for a concrete concept, fine</span></span>
<span id="cb34-7"><a href="#cb34-7"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R<span class="op">&gt;</span></span>
<span id="cb34-8"><a href="#cb34-8"></a>concept_map GetStopToken<span class="op">&lt;</span>receiver<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span> <span class="op">{</span></span>
<span id="cb34-9"><a href="#cb34-9"></a>    <span class="kw">auto</span> get_stop_token<span class="op">(</span>receiver<span class="op">&lt;</span>R<span class="op">&gt;</span> <span class="kw">const</span><span class="op">&amp;)</span> <span class="kw">const</span> <span class="op">-&gt;</span> std<span class="op">::</span>never_stop_token <span class="op">{</span></span>
<span id="cb34-10"><a href="#cb34-10"></a>        <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb34-11"><a href="#cb34-11"></a>    <span class="op">}</span></span>
<span id="cb34-12"><a href="#cb34-12"></a><span class="op">}</span>;</span>
<span id="cb34-13"><a href="#cb34-13"></a></span>
<span id="cb34-14"><a href="#cb34-14"></a><span class="co">// for an arbitrary one?? Well, whatever concept this is, C, needs to be satisfies by R</span></span>
<span id="cb34-15"><a href="#cb34-15"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span><span class="op">&gt;</span> <span class="kw">concept</span> C, C R<span class="op">&gt;</span></span>
<span id="cb34-16"><a href="#cb34-16"></a>concept_map C<span class="op">&lt;</span>receiver<span class="op">&lt;</span>R<span class="op">&gt;&gt;</span></span>
<span id="cb34-17"><a href="#cb34-17"></a><span class="op">{</span></span>
<span id="cb34-18"><a href="#cb34-18"></a>    <span class="co">// but what in the world do we put here???</span></span>
<span id="cb34-19"><a href="#cb34-19"></a>    <span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> Self, <span class="kw">typename</span><span class="op">...</span> Args<span class="op">&gt;</span></span>
<span id="cb34-20"><a href="#cb34-20"></a>    <span class="kw">auto</span> <span class="op">???(</span><span class="kw">this</span> Self<span class="op">&amp;&amp;</span> r, Args<span class="op">&amp;&amp;...</span> args<span class="op">)</span> <span class="op">-&gt;</span> <span class="kw">decltype</span><span class="op">(</span><span class="kw">auto</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb34-21"><a href="#cb34-21"></a>        <span class="cf">return</span> <span class="op">???(</span>FWD<span class="op">(</span>r<span class="op">).</span>inner, FWD<span class="op">(</span>args<span class="op">)...)</span>;</span>
<span id="cb34-22"><a href="#cb34-22"></a>    <span class="op">}</span></span>
<span id="cb34-23"><a href="#cb34-23"></a><span class="op">}</span></span></code></pre></div>
<p>Customization point functions give us an aswer - since the customization point function itself is an object that gives us some nice properties. But in this concepts model, not so much.</p>
<h2 data-number="3.4" id="the-contenders"><span class="header-section-number">3.4</span> The contenders<a href="#the-contenders" class="self-link"></a></h2>
<p>Let’s append customization forwarding to our table and drop all the other options I’ve discussed thus far, save for three:</p>
<table>
<thead>
<tr class="header">
<th>
</th>
<th>
<code class="sourceCode cpp">tag_invoke</code>
</th>
<th>
customization<br />point functions
</th>
<th>
C++0x<br />Concepts
</th>
</tr>
</th>
<tbody>
<tr>
<td>
Interface visible in code
</td>
<td>
❌
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Providing default implementations
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Explicit opt-in
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Diagnose incorrect opt-in
</td>
<td>
🤷
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Easily invoke the customization
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Verify implementation
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Atomic grouping of functionality
</td>
<td>
❌
</td>
<td>
❌
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Non-intrusive
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Associated Types
</td>
<td>
🤷
</td>
<td>
🤷
</td>
<td>
✔️
</td>
</tr>
<tr>
<td>
Forwarding Customizations
</td>
<td>
✔️
</td>
<td>
✔️
</td>
<td>
❌
</td>
</tr>
</tbody>
</table>
<p>I’m giving customization point functions credit for customization forwarding, even though that paper makes no mention of such a thing, since at least I’m under the impression that it’s a direction that could be pursued.</p>
<p><code class="sourceCode cpp">tag_invoke</code> is an improvement over customization point objects as a library solution to the static polymorphism problem. But I don’t really think it’s better enough, and we really need a language solution to this problem. I’m hoping this paper is a good starting point for a discussion, at least.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="bibliography"><span class="header-section-number">4</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references hanging-indent" role="doc-bibliography">
<div id="ref-fmtlib">
<p>[fmtlib] Victor Zverovich. 2012. fmtlib. <br />
<a href="https://fmt.dev/latest/index.html">https://fmt.dev/latest/index.html</a></p>
</div>
<div id="ref-N1758">
<p>[N1758] J. Siek, D. Gregor et al. 2005-01-17. Concepts for C++0x. <br />
<a href="https://wg21.link/n1758">https://wg21.link/n1758</a></p>
</div>
<div id="ref-N2042">
<p>[N2042] D. Gregor, B. Stroustrup. 2006-06-24. Concepts. <br />
<a href="https://wg21.link/n2042">https://wg21.link/n2042</a></p>
</div>
<div id="ref-N4381">
<p>[N4381] Eric Niebler. 2015-03-11. Suggested Design for Customization Points. <br />
<a href="https://wg21.link/n4381">https://wg21.link/n4381</a></p>
</div>
<div id="ref-P1209R0">
<p>[P1209R0] Alisdair Meredith, Stephan T. Lavavej. 2018-10-04. Adopt Consistent Container Erasure from Library Fundamentals 2 for C++20. <br />
<a href="https://wg21.link/p1209r0">https://wg21.link/p1209r0</a></p>
</div>
<div id="ref-P1292R0">
<p>[P1292R0] Matt Calabrese. 2018-10-08. Customization Point Functions. <br />
<a href="https://wg21.link/p1292r0">https://wg21.link/p1292r0</a></p>
</div>
<div id="ref-P1895R0">
<p>[P1895R0] Lewis Baker, Eric Niebler, Kirk Shoop. 2019-10-08. tag_invoke: A general pattern for supporting customisable functions. <br />
<a href="https://wg21.link/p1895r0">https://wg21.link/p1895r0</a></p>
</div>
<div id="ref-P2175R0">
<p>[P2175R0] Lewis Baker. 2020-12-15. Composable cancellation for sender-based async operations. <br />
<a href="https://wg21.link/p2175r0">https://wg21.link/p2175r0</a></p>
</div>
<div id="ref-P2237R0">
<p>[P2237R0] Andrew Sutton. 2020-10-15. Metaprogramming. <br />
<a href="https://wg21.link/p2237r0">https://wg21.link/p2237r0</a></p>
</div>
</div>
</div>
</div>
</body>
</html>
