-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathp2279r0.html
2931 lines (2923 loc) · 202 KB
/
p2279r0.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!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><<a href="mailto:[email protected]" class="email">[email protected]</a>><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"><</span>T, I<span class="op">></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">&</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">&)</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">-></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">&</span></code> for some iterators, <code class="sourceCode cpp">std<span class="op">::</span>string <span class="kw">const</span><span class="op">&</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"><</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"><</span>R<span class="op">></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">></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"><</span><span class="dt">int</span><span class="op">&></span></code> interface and an <code class="sourceCode cpp">InputIterator<span class="op"><</span>std<span class="op">::</span>string <span class="kw">const</span><span class="op">&></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 'container' that compare equal to 'value'</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 'container' pointed to by 'iterator'</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"><</span><span class="kw">typename</span> T<span class="op">></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"><</span><span class="dt">int</span><span class="op">></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"><</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">></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">"{}"</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"><</span>MyType<span class="op">></span></code> to behave like a <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op"><</span>MyType<span class="op">></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"><</span>T<span class="op">>::</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"><</span>U<span class="op">>::</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"><<</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"><</span>I<span class="op">></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"><</span><span class="kw">typename</span> C<span class="op">></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">&</span> c<span class="op">)</span> <span class="op">-></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"><</span><span class="kw">typename</span> T, <span class="dt">size_t</span> N<span class="op">></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">(&</span>a<span class="op">)[</span>N<span class="op">])</span> <span class="op">-></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"><</span><span class="kw">typename</span> C<span class="op">></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">&</span> c<span class="op">)</span> <span class="op">-></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"><</span><span class="kw">typename</span> T, <span class="dt">size_t</span> N<span class="op">></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">(&</span>a<span class="op">)[</span>N<span class="op">])</span> <span class="op">-></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"><</span>R<span class="op">>)</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><source>(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><source>:8:1: error: static_assert failed</span>
<span id="cb10-2"><a href="#cb10-2"></a>static_assert(std::ranges::range<R>);</span>
<span id="cb10-3"><a href="#cb10-3"></a>^ ~~~~~~~~</span>
<span id="cb10-4"><a href="#cb10-4"></a><source>:8:28: note: because 'R' does not satisfy 'range'</span>
<span id="cb10-5"><a href="#cb10-5"></a>static_assert(std::ranges::range<R>);</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 'ranges::begin(__t)' would be invalid: no matching function for call to object of type 'const __cust_access::_Begin'</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><source>:8:28: error: static assertion failed</span>
<span id="cb11-2"><a href="#cb11-2"></a> 8 | static_assert(std::ranges::range<R>);</span>
<span id="cb11-3"><a href="#cb11-3"></a> | ~~~~~~~~~~~~~^~~~~~~~</span>
<span id="cb11-4"><a href="#cb11-4"></a><source>: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 <source>: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 'template<class _Tp> concept std::ranges::range'</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 '_Tp& __t' [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 'std::ranges::__cust::begin(__t)' 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 'std::ranges::__cust::end(__t)' 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 '-fconcepts-diagnostics-depth=' 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><source>:8:28: error: static assertion failed</span>
<span id="cb12-2"><a href="#cb12-2"></a> 8 | static_assert(std::ranges::range<R>);</span>
<span id="cb12-3"><a href="#cb12-3"></a> | ~~~~~~~~~~~~~^~~~~~~~</span>