-
Notifications
You must be signed in to change notification settings - Fork 22
/
d2011r2.html
2142 lines (2134 loc) · 244 KB
/
d2011r2.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="2020-06-30" />
<title>A pipeline-rewrite operator</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">A pipeline-rewrite operator</h1>
<table style="border:none;float:right">
<tr>
<td>Document #:</td>
<td>D2011R2</td>
</tr>
<tr>
<td>Date:</td>
<td>2020-06-30</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>
Colby Pike<br><<a href="mailto:vectorofbool@gmail.com" class="email">vectorofbool@gmail.com</a>><br>
Barry Revzin<br><<a href="mailto:barry.revzin@gmail.com" class="email">barry.revzin@gmail.com</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="#revision-history"><span class="toc-section-number">1</span> Revision History<span></span></a></li>
<li><a href="#abstract"><span class="toc-section-number">2</span> Abstract<span></span></a></li>
<li><a href="#introduction-and-motivation"><span class="toc-section-number">3</span> Introduction and Motivation<span></span></a>
<ul>
<li><a href="#pipeline-style"><span class="toc-section-number">3.1</span> Pipeline Style<span></span></a></li>
<li><a href="#supporting-as-an-pipeline-operator"><span class="toc-section-number">3.2</span> Supporting <code class="sourceCode cpp"><span class="op">|</span></code> as an Pipeline Operator<span></span></a></li>
<li><a href="#problems-with-as-a-pipeline-operator"><span class="toc-section-number">3.3</span> Problems with <code class="sourceCode cpp"><span class="op">|</span></code> as a Pipeline Operator<span></span></a></li>
<li><a href="#ambiguity-problems-with-as-a-pipeline-operator"><span class="toc-section-number">3.4</span> Ambiguity problems with <code class="sourceCode cpp"><span class="op">|</span></code> as a Pipeline Operator<span></span></a></li>
</ul></li>
<li><a href="#proposal-rewriting-pipelines-with-a-operator"><span class="toc-section-number">4</span> Proposal: Rewriting Pipelines with a <code class="sourceCode cpp"><span class="op">|></span></code> Operator<span></span></a>
<ul>
<li><a href="#a-few-more-examples"><span class="toc-section-number">4.1</span> A few more examples<span></span></a></li>
<li><a href="#further-examples"><span class="toc-section-number">4.2</span> Further examples<span></span></a></li>
<li><a href="#prior-art-in-c-and-elsewhere"><span class="toc-section-number">4.3</span> Prior Art (in C++ and elsewhere)<span></span></a></li>
</ul></li>
<li><a href="#operator-precedence"><span class="toc-section-number">5</span> Operator Precedence<span></span></a></li>
<li><a href="#a-placeholder-syntax"><span class="toc-section-number">6</span> A Placeholder syntax<span></span></a></li>
<li><a href="#concerns-with-the-pipeline-operator"><span class="toc-section-number">7</span> Concerns with the Pipeline Operator<span></span></a>
<ul>
<li><a href="#what-about-unified-function-call-syntax"><span class="toc-section-number">7.1</span> What about Unified Function Call Syntax?<span></span></a></li>
<li><a href="#what-about-pipeline-composition"><span class="toc-section-number">7.2</span> What about pipeline composition?<span></span></a></li>
<li><a href="#what-to-do-about-ranges-going-forward"><span class="toc-section-number">7.3</span> What to do about Ranges going forward?<span></span></a></li>
<li><a href="#other-concerns"><span class="toc-section-number">7.4</span> Other Concerns<span></span></a></li>
</ul></li>
<li><a href="#wording"><span class="toc-section-number">8</span> Wording<span></span></a></li>
<li><a href="#acknowledgments"><span class="toc-section-number">9</span> Acknowledgments<span></span></a></li>
<li><a href="#bibliography"><span class="toc-section-number">10</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="revision-history" data-number="1" style="border-bottom:1px solid #cccccc"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>R0 of this paper <span class="citation" data-cites="P2011R0">[<a href="#ref-P2011R0" role="doc-biblioref">P2011R0</a>]</span> was presented in Prague <span class="citation" data-cites="prague.minutes">[<a href="#ref-prague.minutes" role="doc-biblioref">prague.minutes</a>]</span>. The room encouraged further work on the proposal (16-0) and the discussion largely focused on the question of operator precedence, where we were asked to explore giving <code class="sourceCode cpp"><span class="op">|></span></code> a lower precedence than <code class="sourceCode cpp"><span class="op">.</span></code> or <code class="sourceCode cpp"><span class="op">-></span></code> (18-0). That question was also raised on the reflectors <span class="citation" data-cites="ext.precedence">[<a href="#ref-ext.precedence" role="doc-biblioref">ext.precedence</a>]</span>.</p>
<p>This revision lowers the precedence of <code class="sourceCode cpp"><span class="op">|></span></code> (as described in <a href="#operator-precedence">operator precedence</a> and includes discussions of <a href="#what-to-do-about-ranges-going-forward">what to do about Ranges pipelines</a> in C++23 and also considers the idea of using a <a href="#a-placeholder-syntax">placeholder syntax</a>.</p>
<p>This revision also expands the kinds of expressions that can be pipelined into to additionally include casts and explicit type conversion.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="abstract" data-number="2" style="border-bottom:1px solid #cccccc"><span class="header-section-number">2</span> Abstract<a href="#abstract" class="self-link"></a></h1>
<p>This paper proposes a new non-overloadable operator <code class="sourceCode cpp"><span class="op">|></span></code> such that the expression <code class="sourceCode cpp">x <span class="op">|></span> f<span class="op">(</span>y<span class="op">)</span></code> evaluates exactly as <code class="sourceCode cpp">f<span class="op">(</span>x, y<span class="op">)</span></code>. There would be no intermediate subexpression <code class="sourceCode cpp">f<span class="op">(</span>y<span class="op">)</span></code>.</p>
<p>This is notably unrelated to, and quite different from, <span class="citation" data-cites="P1282R0">[<a href="#ref-P1282R0" role="doc-biblioref">P1282R0</a>]</span>, which proposed an overloadable <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">|></span></code>, allowing the evaluation of the above expression as <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">|>(</span>x, f<span class="op">(</span>y<span class="op">))</span></code>.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="introduction-and-motivation" data-number="3" style="border-bottom:1px solid #cccccc"><span class="header-section-number">3</span> Introduction and Motivation<a href="#introduction-and-motivation" class="self-link"></a></h1>
<p>While the addition of Ranges into the standard brings many great features and concepts, the “pipeline” features could use some attention. The current incarnation of the pipeline functionality brings a few important drawbacks:</p>
<ol type="1">
<li>The necessary amount of supporting code machinery lends itself to high amounts of complexity, creating a larger maintenance burden on developers who wish to use and write pipeline-style code.</li>
<li>The support machinery can incur large amounts of overhead when inlining and peephole optimizations are not enabled.</li>
<li>The support machinery places additional large burdens on the implementation in that it needs to parse and process large amounts of the support code that is needed to support the syntax.</li>
<li>Adopting the ability to add pipeline support for some algorithms might be impossible given <a href="#ambiguity-problems-with-as-a-pipeline-operator">fundamental ambiguities</a>.</li>
</ol>
<p>The goal of the “pipeline-rewrite” operator proposed herein is to solve all of the above issues, as well as generalize the concept of “pipeline” code to work with arbitrary functions and types, and not just those that must specifically request it. We elaborate on some of these issues when we talk about the <a href="#problems-with-as-a-pipeline-operator">problems with <code class="sourceCode cpp"><span class="op">|</span></code> as a pipeline operator</a>.</p>
<p>The addition of a “pipeline-rewrite” operator requires no API adjustments to any existing or proposed libraries in order to support such an operator.</p>
<h2 data-number="3.1" id="pipeline-style" data-number="3.1"><span class="header-section-number">3.1</span> Pipeline Style<a href="#pipeline-style" class="self-link"></a></h2>
<p>We have seen the proliferations of generic algorithms being implemented as free functions. For example, where many languages have a single type to represent a “sequence” of values, C++ permits an unlimited number of “sequence” types tailored to the needs of their respective domain, and the generic algorithms that operate on them work identically (provided the underlying type meets the appropriate guarantees). In classical object-oriented languages, the algorithms are attached to the objects themselves. For example:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1"></a><span class="co">// Some JavaScript</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">const</span> seq <span class="op">=</span> [<span class="dv">1</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> <span class="dv">3</span><span class="op">,</span> <span class="dv">4</span>]<span class="op">;</span></span>
<span id="cb1-3"><a href="#cb1-3"></a><span class="kw">const</span> twice <span class="op">=</span> <span class="va">seq</span>.<span class="at">map</span>(i <span class="kw">=></span> i <span class="op">*</span> <span class="dv">2</span>)<span class="op">;</span></span></code></pre></div>
<p>Here <code class="sourceCode cpp">map</code> is a <em>member</em> of <code class="sourceCode cpp">seq</code>, despite the concept of “mapping” being entirely abstract.</p>
<p>In many languages, when new sequence types are needed, they may be defined, but can suffer from performance penalties, but even worse: The algorithms are gone! The algorithm methods need to be re-implemented again on the new types.</p>
<p>The C++ standard library instead opts for generic free functions. These have great benefits, including supporting containers of disparate types:</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="ex">QList</span><span class="op"><</span><span class="dt">int</span><span class="op">></span> integers <span class="op">=</span> get_integers<span class="op">()</span>;</span>
<span id="cb1-2"><a href="#cb1-2"></a>std<span class="op">::</span>vector<span class="op"><</span><span class="dt">int</span><span class="op">></span> twice;</span>
<span id="cb1-3"><a href="#cb1-3"></a>std<span class="op">::</span>transform<span class="op">(</span>begin<span class="op">(</span>integers<span class="op">)</span>, end<span class="op">(</span>integers<span class="op">)</span>, back_inserter<span class="op">(</span>twice<span class="op">)</span>,</span>
<span id="cb1-4"><a href="#cb1-4"></a> <span class="op">[](</span><span class="dt">int</span> i<span class="op">){</span> <span class="cf">return</span> i<span class="op">*</span><span class="dv">2</span>; <span class="op">})</span>;</span></code></pre></div>
<p>Much of the standard library accepts “iterator pairs” as their representation of a sequence. This has some benefits, such as the algorithms not needing to know anything about the underlying container. This also has some drawbacks, such as algorithms not being able to know anything about the underlying container.</p>
<p>One of the biggest drawbacks, though, is the simple verbosity. We do not often write application code dealing strictly with iterator pairs. Instead, we’ll be using actual concrete data structures that expose the iterator pairs that we hand to algorithms.</p>
<p>Amongst many other things, Ranges defines new overloads for many of the standard algorithms that accept range types which represent iterator pairs (or an iterator and a sentinel, but that isn’t relevant).</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="ex">QList</span><span class="op"><</span><span class="dt">int</span><span class="op">></span> integers <span class="op">=</span> get_integers<span class="op">()</span>;</span>
<span id="cb2-2"><a href="#cb2-2"></a>std<span class="op">::</span>vector<span class="op"><</span><span class="dt">int</span><span class="op">></span> twice;</span>
<span id="cb2-3"><a href="#cb2-3"></a>ranges<span class="op">::</span>transform<span class="op">(</span>integers, back_inserter<span class="op">(</span>twice<span class="op">)</span>,</span>
<span id="cb2-4"><a href="#cb2-4"></a> <span class="op">[](</span><span class="dt">int</span> i<span class="op">){</span> <span class="cf">return</span> i<span class="op">*</span><span class="dv">2</span>; <span class="op">})</span>;</span></code></pre></div>
<p>Another idea introduced by Ranges is the composition of algorithms.</p>
<p>Here, we will borrow one of the most famous examples from the ranges-v3 library: The calendar printing example <span class="citation" data-cites="range.calendar">[<a href="#ref-range.calendar" role="doc-biblioref">range.calendar</a>]</span>. We will start with a very uglified version of the example’s apex, <code class="sourceCode cpp">format_calendar</code>:</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> Calendar<span class="op">></span></span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="kw">auto</span> format_calendar<span class="op">(</span><span class="dt">size_t</span> months_per_line, Calendar<span class="op">&&</span> cal<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3"></a> <span class="co">// Group the dates by month</span></span>
<span id="cb3-4"><a href="#cb3-4"></a> <span class="kw">auto</span> months <span class="op">=</span> by_month<span class="op">(</span>cal<span class="op">)</span>;</span>
<span id="cb3-5"><a href="#cb3-5"></a> <span class="co">// Format the months into a range of strings</span></span>
<span id="cb3-6"><a href="#cb3-6"></a> <span class="kw">auto</span> month_strings <span class="op">=</span> layout_months<span class="op">(</span>months<span class="op">)</span>;</span>
<span id="cb3-7"><a href="#cb3-7"></a> <span class="co">// Group the months that belong side-by-side</span></span>
<span id="cb3-8"><a href="#cb3-8"></a> <span class="kw">auto</span> chunked_months <span class="op">=</span> chunk<span class="op">(</span>month_strings, months_per_line<span class="op">)</span>;</span>
<span id="cb3-9"><a href="#cb3-9"></a> <span class="co">// Transpose the rows and columns of side-by-side months</span></span>
<span id="cb3-10"><a href="#cb3-10"></a> <span class="kw">auto</span> transposed <span class="op">=</span> transpose_months<span class="op">(</span>chunked_months<span class="op">)</span>;</span>
<span id="cb3-11"><a href="#cb3-11"></a> <span class="co">// Ungroup the side-by-side months</span></span>
<span id="cb3-12"><a href="#cb3-12"></a> <span class="kw">auto</span> joined_view <span class="op">=</span> view<span class="op">::</span>join<span class="op">(</span>transposed<span class="op">)</span>;</span>
<span id="cb3-13"><a href="#cb3-13"></a> <span class="co">// Join the strings of the transposed months</span></span>
<span id="cb3-14"><a href="#cb3-14"></a> <span class="cf">return</span> join_months<span class="op">(</span>joined_view<span class="op">)</span>;</span>
<span id="cb3-15"><a href="#cb3-15"></a><span class="op">}</span></span></code></pre></div>
<p>This code is not inscrutable, but it is far from what the original looked like. We have a several variables that are essentially meaningless, as their names are tautological to the spelling of their initializing expression. And because these variables are only used in the immediately following line, we may as well place each variable’s initializer in place of the variable name in the following call. The result is horrific, to say the least:</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="kw">template</span> <span class="op"><</span><span class="kw">typename</span> Calendar<span class="op">></span></span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="kw">auto</span> format_calendar<span class="op">(</span><span class="dt">size_t</span> months_per_line, Calendar<span class="op">&&</span> cal<span class="op">)</span> <span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3"></a> <span class="co">// Join the strings of the transposed months</span></span>
<span id="cb4-4"><a href="#cb4-4"></a> <span class="cf">return</span> join_months<span class="op">(</span></span>
<span id="cb4-5"><a href="#cb4-5"></a> <span class="co">// Ungroup the side-by-side months</span></span>
<span id="cb4-6"><a href="#cb4-6"></a> view<span class="op">::</span>join<span class="op">(</span></span>
<span id="cb4-7"><a href="#cb4-7"></a> <span class="co">// Transpose the rows and columns of side-by-side months</span></span>
<span id="cb4-8"><a href="#cb4-8"></a> transpose_months<span class="op">(</span></span>
<span id="cb4-9"><a href="#cb4-9"></a> <span class="co">// Group the months that belong side-by-side</span></span>
<span id="cb4-10"><a href="#cb4-10"></a> chunk<span class="op">(</span></span>
<span id="cb4-11"><a href="#cb4-11"></a> <span class="co">// Format the months into a range of strings</span></span>
<span id="cb4-12"><a href="#cb4-12"></a> layout_months<span class="op">(</span></span>
<span id="cb4-13"><a href="#cb4-13"></a> <span class="co">// Group the dates by month</span></span>
<span id="cb4-14"><a href="#cb4-14"></a> by_month<span class="op">(</span>cal<span class="op">)</span></span>
<span id="cb4-15"><a href="#cb4-15"></a> <span class="op">)</span>,</span>
<span id="cb4-16"><a href="#cb4-16"></a> months_per_line</span>
<span id="cb4-17"><a href="#cb4-17"></a> <span class="op">)</span></span>
<span id="cb4-18"><a href="#cb4-18"></a> <span class="op">)</span></span>
<span id="cb4-19"><a href="#cb4-19"></a> <span class="op">)</span></span>
<span id="cb4-20"><a href="#cb4-20"></a> <span class="op">)</span>;</span>
<span id="cb4-21"><a href="#cb4-21"></a><span class="op">}</span></span></code></pre></div>
<p>(Our favorite feature of the above horror is the <code class="sourceCode cpp">months_per_line</code> appearing quite distant from the function call to which it is an argument.)</p>
<p>While the code is frightening, it is conceptually equivalent to the prior example. Both of these examples are very dissimilar to the code found in the range-v3 <span class="citation" data-cites="range-v3">[<a href="#ref-range-v3" role="doc-biblioref">range-v3</a>]</span> example upon which they were based.</p>
<p>Ranges also seeks to tackle the above problem with the idea of pipeable objects.</p>
<p>Pipeline-style is an increasingly popular way to write code, especially in functional programming languages. Ranges provides pipeline style via overloading of the bitwise-or <code class="sourceCode cpp"><span class="op">|</span></code> binary operator. In the pipeline style, the value on the left of the “pipeline” operator is conceptually “fed into” the expression on the right, where the right-hand-side is some “partial” expression missing the primary argument on which it operates. The actual example from range-v3 uses this syntax to produce the much more concise and readable pipeline style:</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">auto</span></span>
<span id="cb5-2"><a href="#cb5-2"></a>format_calendar<span class="op">(</span>std<span class="op">::</span><span class="dt">size_t</span> months_per_line<span class="op">)</span></span>
<span id="cb5-3"><a href="#cb5-3"></a><span class="op">{</span></span>
<span id="cb5-4"><a href="#cb5-4"></a> <span class="cf">return</span> make_pipeable<span class="op">([=](</span><span class="kw">auto</span> <span class="op">&&</span>rng<span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-5"><a href="#cb5-5"></a> <span class="kw">using</span> Rng <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>rng<span class="op">)</span>;</span>
<span id="cb5-6"><a href="#cb5-6"></a> <span class="cf">return</span> std<span class="op">::</span>forward<span class="op"><</span>Rng<span class="op">>(</span>rng<span class="op">)</span></span>
<span id="cb5-7"><a href="#cb5-7"></a> <span class="co">// Group the dates by month:</span></span>
<span id="cb5-8"><a href="#cb5-8"></a> <span class="op">|</span> by_month<span class="op">()</span></span>
<span id="cb5-9"><a href="#cb5-9"></a> <span class="co">// Format the month into a range of strings:</span></span>
<span id="cb5-10"><a href="#cb5-10"></a> <span class="op">|</span> layout_months<span class="op">()</span></span>
<span id="cb5-11"><a href="#cb5-11"></a> <span class="co">// Group the months that belong side-by-side:</span></span>
<span id="cb5-12"><a href="#cb5-12"></a> <span class="op">|</span> chunk<span class="op">(</span>months_per_line<span class="op">)</span></span>
<span id="cb5-13"><a href="#cb5-13"></a> <span class="co">// Transpose the rows and columns of the size-by-side months:</span></span>
<span id="cb5-14"><a href="#cb5-14"></a> <span class="op">|</span> transpose_months<span class="op">()</span></span>
<span id="cb5-15"><a href="#cb5-15"></a> <span class="co">// Ungroup the side-by-side months:</span></span>
<span id="cb5-16"><a href="#cb5-16"></a> <span class="op">|</span> view<span class="op">::</span>join</span>
<span id="cb5-17"><a href="#cb5-17"></a> <span class="co">// Join the strings of the transposed months:</span></span>
<span id="cb5-18"><a href="#cb5-18"></a> <span class="op">|</span> join_months<span class="op">()</span>;</span>
<span id="cb5-19"><a href="#cb5-19"></a> <span class="op">})</span>;</span>
<span id="cb5-20"><a href="#cb5-20"></a><span class="op">}</span></span></code></pre></div>
<p>Usage of <code class="sourceCode cpp">format_calendar</code> also makes use of the “pipeline” syntax:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a>copy<span class="op">(</span>dates<span class="op">(</span>start_date, end_state<span class="op">)</span> <span class="op">|</span> format_calendar<span class="op">(</span><span class="dv">3</span><span class="op">)</span>,</span>
<span id="cb6-2"><a href="#cb6-2"></a> calendar_lines<span class="op">)</span>;</span></code></pre></div>
<p>Where <code class="sourceCode cpp">dates</code> lazily generates date objects which are fed into the <code class="sourceCode cpp">format_calendar</code> algorithm.</p>
<p>Although the above examples use ranges, the pipeline style can be applied to any type of objects, from integers to strings to database rows.</p>
<h2 data-number="3.2" id="supporting-as-an-pipeline-operator" data-number="3.2"><span class="header-section-number">3.2</span> Supporting <code class="sourceCode cpp"><span class="op">|</span></code> as an Pipeline Operator<a href="#supporting-as-an-pipeline-operator" class="self-link"></a></h2>
<p>How does <code class="sourceCode cpp"><span class="op">|</span></code> work in the above examples, and with Ranges in general? After all, it’s just the bitwise-or operator. The “pipeline” semantics aren’t built into the language.</p>
<p>The answer, of course, is to use operator overloading. To support <code class="sourceCode cpp">transform<span class="op">(</span>rng, projection<span class="op">)</span></code> and <code class="sourceCode cpp">rng <span class="op">|</span> transform<span class="op">(</span>projection<span class="op">)</span></code>, the <code class="sourceCode cpp">transform</code> name does not correspond to a single function. It must instead name an overload set (or, as with everything in Ranges, a single object with multiple <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">()</span></code> overloads). The type returned by the two overloads is radically different. The partially-applied form intended for use with <code class="sourceCode cpp"><span class="op">|</span></code> stores its argument in an object which defines the overloaded <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">|</span></code>. If a range is given as the left-hand operand of the <code class="sourceCode cpp"><span class="op">|</span></code> operator, only then is the algorithm fully-applied and ready to produce results.</p>
<p>Let’s go through what the implementation of this machinery looks like so that we can point out what the many issues with it are.</p>
<p>For the full function call, <code class="sourceCode cpp">transform<span class="op">(</span>rng, projection<span class="op">)</span></code>, we can provide complete constraints. We have all the information we need: we know the range, we know the function type, and we know that the function type has to be compatible with the range. With concepts, we just need to write those constraints out:</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">template</span> <span class="op"><</span>std<span class="op">::</span>ranges<span class="op">::</span>viewable_range R,</span>
<span id="cb7-2"><a href="#cb7-2"></a> std<span class="op">::</span>regular_invocable<span class="op"><</span>std<span class="op">::</span>range_reference_t<span class="op"><</span>R<span class="op">>></span> F<span class="op">></span></span>
<span id="cb7-3"><a href="#cb7-3"></a><span class="kw">auto</span> transform<span class="op">(</span>R<span class="op">&&</span> range, F<span class="op">&&</span> projection<span class="op">)</span></span>
<span id="cb7-4"><a href="#cb7-4"></a> <span class="op">-></span> transform_view<span class="op"><</span>std<span class="op">::</span>ranges<span class="op">::</span>all_view<span class="op"><</span>R<span class="op">></span>, std<span class="op">::</span>decay_t<span class="op"><</span>F<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 class="co">// implementation</span></span>
<span id="cb7-7"><a href="#cb7-7"></a><span class="op">}</span></span></code></pre></div>
<p>Now the implementation of <code class="sourceCode cpp">transform_view</code> itself is non-trivial - but its implementation is unrelated to the topic we’re focusing on here.</p>
<p>Now for the partial function call, in order to support <code class="sourceCode cpp">rng <span class="op">|</span> transform<span class="op">(</span>f<span class="op">)</span></code> we need to first support <code class="sourceCode cpp">transform<span class="op">(</span>f<span class="op">)</span></code>. This call does not have complete information - we just have a function, but we cannot check this function all by itself. We can only check if a type is callable with a specific argument, we cannot check in general if a type is callable at all. There is no constraint that we can add on this type at all (outside of it being copyable), so we’re left to just write:</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="pp">#define FWD</span><span class="op">(</span>x<span class="op">)</span><span class="pp"> </span><span class="kw">static_cast</span><span class="op"><</span><span class="kw">decltype</span><span class="op">(</span>x<span class="op">)&&>(</span>x<span class="op">)</span></span>
<span id="cb8-2"><a href="#cb8-2"></a></span>
<span id="cb8-3"><a href="#cb8-3"></a><span class="kw">template</span> <span class="op"><</span><span class="kw">typename</span> F<span class="op">></span></span>
<span id="cb8-4"><a href="#cb8-4"></a><span class="kw">auto</span> transform<span class="op">(</span>F<span class="op">&&</span> projection<span class="op">)</span></span>
<span id="cb8-5"><a href="#cb8-5"></a><span class="op">{</span></span>
<span id="cb8-6"><a href="#cb8-6"></a> <span class="cf">return</span> make_left_pipeable<span class="op">(</span></span>
<span id="cb8-7"><a href="#cb8-7"></a> <span class="op">[</span>f<span class="op">=</span>std<span class="op">::</span>forward<span class="op"><</span>F<span class="op">>(</span>projection<span class="op">)](</span>std<span class="op">::</span>ranges<span class="op">::</span>viewable_range <span class="kw">auto</span><span class="op">&&</span> r<span class="op">)</span></span>
<span id="cb8-8"><a href="#cb8-8"></a> <span class="op">-></span> <span class="kw">decltype</span><span class="op">(</span>transform<span class="op">(</span>FWD<span class="op">(</span>r<span class="op">)</span>, std<span class="op">::</span>ref<span class="op">(</span>f<span class="op">)))</span></span>
<span id="cb8-9"><a href="#cb8-9"></a> <span class="op">{</span></span>
<span id="cb8-10"><a href="#cb8-10"></a> <span class="cf">return</span> transform<span class="op">(</span>FWD<span class="op">(</span>r<span class="op">)</span>, std<span class="op">::</span>ref<span class="op">(</span>f<span class="op">))</span>;</span>
<span id="cb8-11"><a href="#cb8-11"></a> <span class="op">})</span>;</span>
<span id="cb8-12"><a href="#cb8-12"></a><span class="op">}</span></span></code></pre></div>
<p>This is probably the most concise way to implement partial <code class="sourceCode cpp">transform</code>: we have a utility <code class="sourceCode cpp">make_left_pipeable</code> which takes a lambda and returns a type that, when left-<code class="sourceCode cpp"><span class="op">|</span></code>-ed invokes the lambda. This lambda has to be SFINAE-friendly, and needs to just forward all of its arguments properly to the complete call so as to avoid having to duplicate the constraints.</p>
<h2 data-number="3.3" id="problems-with-as-a-pipeline-operator" data-number="3.3"><span class="header-section-number">3.3</span> Problems with <code class="sourceCode cpp"><span class="op">|</span></code> as a Pipeline Operator<a href="#problems-with-as-a-pipeline-operator" class="self-link"></a></h2>
<p>There are a few facially obvious drawbacks to using <code class="sourceCode cpp"><span class="op">|</span></code> for pipeline semantics:</p>
<ul>
<li>The code required to support using <code class="sourceCode cpp"><span class="op">|</span></code> functionality adds overhead during compilation, and without the aide of the inliner and basic optimizations it can be expensive at runtime.</li>
<li>Defining new range algorithms necessitates opting-in to this machinery. Existing code cannot make use of pipeline style.</li>
<li>Supporting both pipeline style and immediate style requires algorithms to provide both partial and full algorithm implementations, where the partial implementation is mostly boilerplate to generate the partially applied closure object.</li>
</ul>
<p>We showed in the previous section how a <code class="sourceCode cpp"><span class="op">|</span></code>-friendly <code class="sourceCode cpp">transform_view</code> could be implemented. Could this be improved in a different way, perhaps with reflection? This seems, at least, theoretically possible. The algorithm would be: take the “full call”, strip the first argument and strip all the constraints that (recursively) require the first argument). Then have the body be a lambda that takes a single argument, captures the function parameters by forward, and re-instances the constraints that were stripped from the original algorithm. A much simpler (and probably <em>mostly</em>) would be to generate a partial call version that is:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1"></a><span class="kw">auto</span> transform<span class="op">(</span><span class="kw">auto</span><span class="op">&&...</span> args<span class="op">)</span></span>
<span id="cb9-2"><a href="#cb9-2"></a><span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3"></a> <span class="cf">return</span> make_left_pipeable<span class="op">(</span></span>
<span id="cb9-4"><a href="#cb9-4"></a> <span class="op">[...</span>args<span class="op">=</span>FWD<span class="op">(</span>args<span class="op">)](</span><span class="co">/* no constraint */</span> <span class="kw">auto</span><span class="op">&&</span> first<span class="op">)</span></span>
<span id="cb9-5"><a href="#cb9-5"></a> <span class="op">-></span> <span class="kw">decltype</span><span class="op">(</span>transform<span class="op">(</span>FWD<span class="op">(</span>first<span class="op">)</span>, FWD<span class="op">(</span>args<span class="op">)...))</span></span>
<span id="cb9-6"><a href="#cb9-6"></a> <span class="op">{</span></span>
<span id="cb9-7"><a href="#cb9-7"></a> <span class="cf">return</span> transform<span class="op">(</span>FWD<span class="op">(</span>first<span class="op">)</span>, FWD<span class="op">(</span>args<span class="op">)...)</span>;</span>
<span id="cb9-8"><a href="#cb9-8"></a> <span class="op">})</span>;</span></code></pre></div>
<p>This one could actually be written as a macro once we write <code class="sourceCode cpp">make_left_pipeable</code> one time.</p>
<p>But even with the simple macro approach (and, spoiler alert, that direction as a whole may not be viable), there’s still cost to consider:</p>
<ul>
<li>while <code class="sourceCode cpp">views<span class="op">::</span>transform<span class="op">(</span>rng, f<span class="op">)</span></code> and <code class="sourceCode cpp">rng <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>f<span class="op">)</span></code> generate identical code in optimized builds, the latter has overhead in debug builds - both in terms of performance and debugability. That makes it not entirely the zero- overhead abstraction that we like to claim, for those users that regularly use debug builds (which is a large percentage of users).</li>
<li>having to deal with the extra <code class="sourceCode cpp"><span class="op">|</span></code> abstraction requires extra parsing on the compiler’s part for each TU (possibly less of an issue in a modules world)</li>
<li>even with modules, this abstraction has compile time cost as <code class="sourceCode cpp">transform</code> now has two overloads (instead of one) regardless of if we use the pipeline syntax or not - and then we need to do an additional overload resolution for the <code class="sourceCode cpp"><span class="op">|</span></code>, all of which are function templates that need to be instantiated.</li>
</ul>
<p>We’ll discuss the second and third points more in the context of what we propose to do about <a href="#what-to-do-about-ranges-going-forward">Ranges going forward</a>.</p>
<p>Those are, in of themselves, far from ideal. But these problems are all just work - work for the programmer to write the initial <code class="sourceCode cpp"><span class="op">|</span></code> support to begin with (just the one time), work for the programmer to write each additional overload to opt-in, work for the compiler to compile all these things together, work for the optimizer to get rid of all these things, work for the programmer to try to figure out what’s getting called where.</p>
<h2 data-number="3.4" id="ambiguity-problems-with-as-a-pipeline-operator" data-number="3.4"><span class="header-section-number">3.4</span> Ambiguity problems with <code class="sourceCode cpp"><span class="op">|</span></code> as a Pipeline Operator<a href="#ambiguity-problems-with-as-a-pipeline-operator" class="self-link"></a></h2>
<p>But there’s a bigger problem here that no amount increased programmer or compiler throughput can solve: sometimes the partial and complete calls are ambiguous.</p>
<p>Specific to ranges, the “total call” syntax always takes a range followed by some amount of helper arguments. In the <code class="sourceCode cpp">transform</code> case, this is a range followed by an invocable. The “partial call” syntax drops the range, and takes the rest of the arguments. What happens, though, when the second argument can itself be a range? How do you know? There are several examples where this comes up:</p>
<ul>
<li><p><code class="sourceCode cpp">zip</code> is a view that takes a bunch of ranges and turns them into a range of <code class="sourceCode cpp">tuple</code>s of references, it’s an extremely useful range adaptor - just one that we won’t quite have in C++20. <code class="sourceCode cpp">zip<span class="op">(</span>a<span class="op">)</span></code> is itself a valid (if odd) view: just takes all the elements of a range and wraps them in a <code class="sourceCode cpp">tuple</code> of a single element. As a result, you cannot make both <code class="sourceCode cpp">zip<span class="op">(</span>a, b<span class="op">)</span></code> and <code class="sourceCode cpp">a <span class="op">|</span> zip<span class="op">(</span>b<span class="op">)</span></code> yield a range of tuples, you have to pick one. range-v3’s <code class="sourceCode cpp">zip</code> does not support the pipeline syntax.</p></li>
<li><p><code class="sourceCode cpp">concat</code> is a view that takes a bunch of ranges and concatenates them all together in a larger range. Much like <code class="sourceCode cpp">zip</code>, <code class="sourceCode cpp">concat<span class="op">(</span>a<span class="op">)</span></code> is a valid expression and so <code class="sourceCode cpp">a <span class="op">|</span> concat<span class="op">(</span>b<span class="op">)</span></code> can’t work. range-v3’s <code class="sourceCode cpp">concat</code> does not support the pipeline syntax.</p></li>
<li><p><code class="sourceCode cpp">transform</code> actually has two forms: a unary form and a binary form. C++20 adds an algorithm that is <code class="sourceCode cpp">ranges<span class="op">::</span>transform<span class="op">(</span>rng1, rng2, result, binary_op<span class="op">)</span></code>. But <code class="sourceCode cpp">views<span class="op">::</span>transform<span class="op">(</span>r, f<span class="op">)</span></code> could be a valid expression, so there may be an ambiguity with <code class="sourceCode cpp">a <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>b, f<span class="op">)</span></code>, if <code class="sourceCode cpp">f</code> happens to be invocable both as a unary and as a binary function. range-v3 does not have a binary transform adapter, only a unary one.</p></li>
<li><p><code class="sourceCode cpp">views<span class="op">::</span>join</code> in C++20 takes a range of ranges and collapses it to a single range, taking no additional arguments. One potentially useful argument it could take is a delimiter: <code class="sourceCode cpp">join<span class="op">(</span>rng_of_rngs, delim<span class="op">)</span></code> could interleave the delimiter in between each element. But can itself be a range of ranges, then you’ll run into problems with <code class="sourceCode cpp">rng <span class="op">|</span> join<span class="op">(</span>delim<span class="op">)</span></code>. range-v3 only considers the pipeable form for non-joinable-ranges. An alternative approach might have to been to just name them differently - <code class="sourceCode cpp">join<span class="op">(</span>rng<span class="op">)</span></code> is unambiguous with <code class="sourceCode cpp">rng <span class="op">|</span> join</code> and <code class="sourceCode cpp">join_with<span class="op">(</span>rng, delim<span class="op">)</span></code> is unambiguous with <code class="sourceCode cpp">rng <span class="op">|</span> join_with<span class="op">(</span>delim<span class="op">)</span></code>.</p></li>
</ul>
<p>Each of these are specific cases that have to be considered by the library author, which is just a lot of extra mental overhead to have to deal with. But it’s somehow even worse than that.</p>
<p>In range-v3 and in C++20, the only algorithms that opt-in to the pipeline syntax are those algorithms that take one or more ranges as input and produce a [lazy] range as output. There is a whole other class of algorithms that does not have this particular shape, but still would be quite useful to have pipeline syntax for. Conor Hoekstra, in his CppNow talk entitled Algorithm Intuition <span class="citation" data-cites="hoekstra">[<a href="#ref-hoekstra" role="doc-biblioref">hoekstra</a>]</span>, presented a problem which boiled down to checking if a string had at least 7 consecutive 0s or 1s. One way to solve that using the pipeline syntax would be:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1"></a><span class="kw">auto</span> dangerous_teams<span class="op">(</span>std<span class="op">::</span>string <span class="kw">const</span><span class="op">&</span> s<span class="op">)</span> <span class="op">-></span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2"></a> <span class="cf">return</span> s</span>
<span id="cb10-3"><a href="#cb10-3"></a> <span class="op">|</span> views<span class="op">::</span>group_by<span class="op">(</span>std<span class="op">::</span>equal_to<span class="op">{})</span></span>
<span id="cb10-4"><a href="#cb10-4"></a> <span class="op">|</span> views<span class="op">::</span>transform<span class="op">(</span>ranges<span class="op">::</span>distance<span class="op">)</span></span>
<span id="cb10-5"><a href="#cb10-5"></a> <span class="op">|</span> ranges<span class="op">::</span>any_of<span class="op">([](</span>std<span class="op">::</span><span class="dt">size_t</span> s<span class="op">){</span></span>
<span id="cb10-6"><a href="#cb10-6"></a> <span class="cf">return</span> s <span class="op">>=</span> <span class="dv">7</span>;</span>
<span id="cb10-7"><a href="#cb10-7"></a> <span class="op">})</span>;</span>
<span id="cb10-8"><a href="#cb10-8"></a><span class="op">}</span></span></code></pre></div>
<p>At least, it would be a way of solving this problem if the <code class="sourceCode cpp">any_of</code> algorithm had opted-in to the pipeline syntax. It does not. And doing so takes work - we have to go through all of the over 100 algorithms in the standard library and add these extra partial overloads, specify how all of them work, and then figure out how to deal with ambiguities. This is a lot of work for a large number of people, and still wouldn’t help solve the problem for any of the algorithms in user code. And you can still get an ambiguity:</p>
<ul>
<li><code class="sourceCode cpp">accumulate</code> does not currently have a range-based overload in C++20, but it needs to take an initial value as the second argument. If that initial argument is a range that happens to be addable, that’s ambiguous. One such type is <code class="sourceCode cpp">std<span class="op">::</span>string</code>: is <code class="sourceCode cpp">accumulate<span class="op">(</span>str<span class="op">)</span></code> a complete call summing that string, or is it a partial call simply providing the initial value to the accumulator. You could work around this - either by not providing a default value for the initial value, or not providing a default value for the binary operator (or both). But either way, you need <em>some</em> workaround. range-v3 does not have a pipeable <code class="sourceCode cpp">accumulate</code>, but it only defaults the binary op and not the initial value - which itself prevents you from writing <code class="sourceCode cpp">accumulate<span class="op">(</span>some_ints<span class="op">)</span></code>.</li>
</ul>
<p>Rather than committing to:</p>
<ul>
<li>a lot of committee time to discuss opting in algorithms to the pipeline syntax, and</li>
<li>a lot of committee time to discuss the right way to handle ambiguities, and</li>
<li>a lot of library implementer time to implement the ones that we adopt, and</li>
<li>a lot of compiler time compling code that uses the pipeline syntax, and</li>
<li>a lot of non-committee time to do the same for their own algorithms, including having to come up with mechanisms to support the pipeline syntax for algorithms like <code class="sourceCode cpp">zip</code> and <code class="sourceCode cpp">concat</code> too.</li>
</ul>
<p>We would like to propose something better.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="proposal-rewriting-pipelines-with-a-operator" data-number="4" style="border-bottom:1px solid #cccccc"><span class="header-section-number">4</span> Proposal: Rewriting Pipelines with a <code class="sourceCode cpp"><span class="op">|></span></code> Operator<a href="#proposal-rewriting-pipelines-with-a-operator" class="self-link"></a></h1>
<p>We propose a new, non-overloaded function call operator spelled <code class="sourceCode cpp"><span class="op">|></span></code>. What it does is simply evaluate:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1"></a>x <span class="op">|></span> f<span class="op">(</span>y<span class="op">)</span></span></code></pre></div>
<p>as</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1"></a>f<span class="op">(</span>x, y<span class="op">)</span></span></code></pre></div>
<p>Without any intermediate operands. That is, it rewrites code written in a pipeline style into immediate function call style. This rewriting of pipeline-style is why the name “pipeline-rewrite” was chosen.</p>
<p>It’s important to be clear that the above <strong>does not</strong> evaluate as:</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">operator</span><span class="op">|>(</span>x, f<span class="op">(</span>y<span class="op">))</span></span></code></pre></div>
<p>There is no <code class="sourceCode cpp">f<span class="op">(</span>y<span class="op">)</span></code> operand, there is no lookup for <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">|></span></code> (this paper is proposing that such a declaration be ill-formed - this operator is not overloadable).</p>
<p>In other words, the following program is valid:</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">constexpr</span> <span class="dt">int</span> add<span class="op">(</span><span class="dt">int</span> a, <span class="dt">int</span> b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb14-2"><a href="#cb14-2"></a> <span class="cf">return</span> a <span class="op">+</span> b;</span>
<span id="cb14-3"><a href="#cb14-3"></a><span class="op">}</span></span>
<span id="cb14-4"><a href="#cb14-4"></a></span>
<span id="cb14-5"><a href="#cb14-5"></a><span class="kw">constexpr</span> <span class="dt">int</span> sum <span class="op">=</span> <span class="dv">1</span> <span class="op">|></span> add<span class="op">(</span><span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb14-6"><a href="#cb14-6"></a><span class="kw">static_assert</span><span class="op">(</span>sum <span class="op">==</span> <span class="dv">3</span><span class="op">)</span>;</span></code></pre></div>
<p>This is a complete program, no <code class="sourceCode cpp"><span class="pp">#include</span></code>s or <code><span class="kw">import</span></code>s, no additional library glue necessary to make this work. The assertion directly invokes <code class="sourceCode cpp">add<span class="op">(</span><span class="dv">1</span>, <span class="dv">2</span><span class="op">)</span></code> just as if the code had been written that way to begin with. Indeed, an attempt at invoking a unary <code class="sourceCode cpp">add<span class="op">(</span><span class="dv">2</span><span class="op">)</span></code> would be ill-formed!</p>
<p>This is similar to member function call syntax, where <code class="sourceCode cpp">c<span class="op">.</span>f<span class="op">(</span>x<span class="op">)</span></code> does not evaluate as the expression <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">.(</span>c, f<span class="op">(</span>x<span class="op">))</span></code> and instead evaluates as something much closer to <code class="sourceCode cpp">C<span class="op">::</span>f<span class="op">(</span>c, x<span class="op">)</span></code></p>
<h2 data-number="4.1" id="a-few-more-examples" data-number="4.1"><span class="header-section-number">4.1</span> A few more examples<a href="#a-few-more-examples" class="self-link"></a></h2>
<p>The description above is roughly the entirety of the proposal. We take the expression on the left-hand side of <code class="sourceCode cpp"><span class="op">|></span></code> and treat it as the first argument of the call expression on the right-hand side of <code class="sourceCode cpp"><span class="op">|></span></code>.</p>
<p>Some more examples:</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> X <span class="op">{</span> <span class="dt">int</span> i; <span class="op">}</span>;</span>
<span id="cb15-3"><a href="#cb15-3"></a> <span class="dt">int</span> f<span class="op">(</span>X x<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> x<span class="op">.</span>i; <span class="op">}</span></span>
<span id="cb15-4"><a href="#cb15-4"></a><span class="op">}</span></span>
<span id="cb15-5"><a href="#cb15-5"></a></span>
<span id="cb15-6"><a href="#cb15-6"></a><span class="kw">template</span> <span class="op"><</span><span class="kw">typename</span> T<span class="op">></span></span>
<span id="cb15-7"><a href="#cb15-7"></a><span class="dt">void</span> f<span class="op">(</span>T<span class="op">)</span>;</span>
<span id="cb15-8"><a href="#cb15-8"></a></span>
<span id="cb15-9"><a href="#cb15-9"></a>N<span class="op">::</span>X<span class="op">{</span><span class="dv">1</span><span class="op">}</span> <span class="op">|></span> f<span class="op">()</span>; <span class="co">// ADL finds N::f, is 1</span></span>
<span id="cb15-10"><a href="#cb15-10"></a>N<span class="op">::</span>X<span class="op">{</span><span class="dv">1</span><span class="op">}</span> <span class="op">|></span> <span class="op">(</span>f<span class="op">)()</span>; <span class="co">// parens inhibit ADL, so this calls `::f`, is a void</span></span>
<span id="cb15-11"><a href="#cb15-11"></a></span>
<span id="cb15-12"><a href="#cb15-12"></a><span class="co">// immediately invokes the lambda with arguments 1 and 2</span></span>
<span id="cb15-13"><a href="#cb15-13"></a><span class="dv">1</span> <span class="op">|></span> <span class="op">[](</span><span class="dt">int</span> i, <span class="dt">int</span> j<span class="op">){</span> <span class="cf">return</span> i <span class="op">+</span> j; <span class="op">}(</span><span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb15-14"><a href="#cb15-14"></a></span>
<span id="cb15-15"><a href="#cb15-15"></a><span class="co">// immediately invokes the lambda with the argument 1</span></span>
<span id="cb15-16"><a href="#cb15-16"></a><span class="dv">1</span> <span class="op">|></span> <span class="op">[](</span><span class="dt">int</span> i<span class="op">){</span> <span class="cf">return</span> i; <span class="op">}()</span>;</span>
<span id="cb15-17"><a href="#cb15-17"></a></span>
<span id="cb15-18"><a href="#cb15-18"></a><span class="kw">template</span> <span class="op"><</span><span class="kw">typename</span> T<span class="op">></span></span>
<span id="cb15-19"><a href="#cb15-19"></a><span class="dt">int</span> g<span class="op">(</span>T<span class="op">)</span>;</span>
<span id="cb15-20"><a href="#cb15-20"></a></span>
<span id="cb15-21"><a href="#cb15-21"></a><span class="dv">2</span> <span class="op">|></span> g<span class="op"><</span><span class="dt">int</span><span class="op">>()</span>; <span class="co">// equivalent to g<int>(2)</span></span>
<span id="cb15-22"><a href="#cb15-22"></a></span>
<span id="cb15-23"><a href="#cb15-23"></a><span class="co">// arbitrary expressions can be composed in parens</span></span>
<span id="cb15-24"><a href="#cb15-24"></a><span class="kw">template</span> <span class="op"><</span><span class="kw">typename</span> F, <span class="kw">typename</span> G<span class="op">></span></span>
<span id="cb15-25"><a href="#cb15-25"></a><span class="kw">auto</span> <span class="kw">operator</span><span class="op">>>(</span>F f, G g<span class="op">)</span> <span class="op">{</span></span>
<span id="cb15-26"><a href="#cb15-26"></a> <span class="cf">return</span> <span class="op">[=](</span><span class="kw">auto</span> arg<span class="op">){</span></span>
<span id="cb15-27"><a href="#cb15-27"></a> <span class="cf">return</span> g<span class="op">(</span>f<span class="op">(</span>arg<span class="op">))</span>;</span>
<span id="cb15-28"><a href="#cb15-28"></a> <span class="op">}</span>;</span>
<span id="cb15-29"><a href="#cb15-29"></a><span class="op">}</span></span>
<span id="cb15-30"><a href="#cb15-30"></a></span>
<span id="cb15-31"><a href="#cb15-31"></a><span class="co">// evaluates as dbl(add1(4))</span></span>
<span id="cb15-32"><a href="#cb15-32"></a><span class="kw">auto</span> add1 <span class="op">=</span> <span class="op">[](</span><span class="dt">int</span> i<span class="op">){</span> <span class="cf">return</span> i<span class="op">+</span><span class="dv">1</span>; <span class="op">}</span>;</span>
<span id="cb15-33"><a href="#cb15-33"></a><span class="kw">auto</span> dbl <span class="op">=</span> <span class="op">[](</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> i<span class="op">*</span><span class="dv">2</span>; <span class="op">}</span>;</span>
<span id="cb15-34"><a href="#cb15-34"></a><span class="dv">4</span> <span class="op">|></span> <span class="op">(</span>add1 <span class="op">>></span> dbl<span class="op">)()</span>;</span></code></pre></div>
<p>All of the above works directly out of the box with this proposal.</p>
<h2 data-number="4.2" id="further-examples" data-number="4.2"><span class="header-section-number">4.2</span> Further examples<a href="#further-examples" class="self-link"></a></h2>
<h3 data-number="4.2.1" id="inside-out-vs-left-to-right" data-number="4.2.1"><span class="header-section-number">4.2.1</span> Inside out vs left-to-right<a href="#inside-out-vs-left-to-right" class="self-link"></a></h3>
<p>Consider trying to trim a <code class="sourceCode cpp">std<span class="op">::</span>string</code>. We could write it this way:</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">auto</span> trim<span class="op">(</span>std<span class="op">::</span>string <span class="kw">const</span><span class="op">&</span> str<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>string</span>
<span id="cb16-2"><a href="#cb16-2"></a><span class="op">{</span></span>
<span id="cb16-3"><a href="#cb16-3"></a> <span class="kw">auto</span> b <span class="op">=</span> ranges<span class="op">::</span>find_if<span class="op">(</span>str, isalpha<span class="op">)</span>;</span>
<span id="cb16-4"><a href="#cb16-4"></a> <span class="kw">auto</span> e <span class="op">=</span> ranges<span class="op">::</span>find_if<span class="op">(</span>str <span class="op">|</span> views<span class="op">::</span>reverse, isalpha<span class="op">).</span>base<span class="op">()</span>;</span>
<span id="cb16-5"><a href="#cb16-5"></a> <span class="cf">return</span> std<span class="op">::</span>string<span class="op">(</span>b, e<span class="op">)</span>;</span>
<span id="cb16-6"><a href="#cb16-6"></a><span class="op">}</span></span></code></pre></div>
<p>It’s hard to interpret what’s going on in that second line due to the inside-out reading that is necessary - there’s a lot of back and forth. With the pipeline rewrite operator, we could rewrite this function to be entirely left-to-right:</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1"></a><span class="kw">auto</span> trim<span class="op">(</span>std<span class="op">::</span>string <span class="kw">const</span><span class="op">&</span> str<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>string</span>
<span id="cb17-2"><a href="#cb17-2"></a><span class="op">{</span></span>
<span id="cb17-3"><a href="#cb17-3"></a> <span class="kw">auto</span> b <span class="op">=</span> str <span class="op">|></span> ranges<span class="op">::</span>find_if<span class="op">(</span>isalpha<span class="op">)</span>;</span>
<span id="cb17-4"><a href="#cb17-4"></a> <span class="kw">auto</span> e <span class="op">=</span> str <span class="op">|></span> views<span class="op">::</span>reverse<span class="op">()</span> <span class="op">|></span> ranges<span class="op">::</span>find_if<span class="op">(</span>isalpha<span class="op">)</span>;</span>
<span id="cb17-5"><a href="#cb17-5"></a> <span class="cf">return</span> std<span class="op">::</span>string<span class="op">(</span>b, e<span class="op">.</span>base<span class="op">())</span>;</span>
<span id="cb17-6"><a href="#cb17-6"></a><span class="op">}</span></span></code></pre></div>
<p>This ordering is a more direct translation of the original thought process: we take our <code class="sourceCode cpp">string</code>, reverse it, find the first alpha character, then get the base iterator out of it.</p>
<p>To make the <code class="sourceCode cpp">ranges<span class="op">::</span>find_if</code> algorithm work with the <code class="sourceCode cpp"><span class="op">|></span></code> operator, we need to write this additional code:</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1"></a><span class="co">// (This space intentionally left blank)</span></span></code></pre></div>
<p>That’s right! Nothing at all!</p>
<p>Remember that the semantics of <code class="sourceCode cpp"><span class="op">|></span></code> will <em>rewrite</em> the 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="co">// This:</span></span>
<span id="cb19-2"><a href="#cb19-2"></a><span class="kw">auto</span> e <span class="op">=</span> str <span class="op">|></span> views<span class="op">::</span>reverse<span class="op">()</span> <span class="op">|></span> ranges<span class="op">::</span>find_if<span class="op">(</span>isalpha<span class="op">)</span>;</span>
<span id="cb19-3"><a href="#cb19-3"></a><span class="co">// becomes this:</span></span>
<span id="cb19-4"><a href="#cb19-4"></a><span class="kw">auto</span> e <span class="op">=</span> ranges<span class="op">::</span>find_if<span class="op">(</span>views<span class="op">::</span>reverse<span class="op">(</span>str<span class="op">)</span>, isalpha<span class="op">)</span>;</span></code></pre></div>
<p>That is, using <code class="sourceCode cpp"><span class="op">|></span></code> is equivalent to the code not using the pipeline style.</p>
<h3 data-number="4.2.2" id="using-copy" data-number="4.2.2"><span class="header-section-number">4.2.2</span> Using <code class="sourceCode cpp">copy</code><a href="#using-copy" class="self-link"></a></h3>
<p>Let’s look at a non-lazy <code class="sourceCode cpp">copy</code> function:</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"><</span><span class="kw">typename</span> Range, <span class="kw">typename</span> Output<span class="op">></span></span>
<span id="cb20-2"><a href="#cb20-2"></a><span class="kw">auto</span> copy<span class="op">(</span>Range<span class="op">&&</span> rng, Output out<span class="op">)</span> <span class="op">{</span></span>
<span id="cb20-3"><a href="#cb20-3"></a> <span class="cf">for</span> <span class="op">(</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&</span> item <span class="op">:</span> std<span class="op">::</span>forward<span class="op"><</span>Range<span class="op">>(</span>rng<span class="op">))</span> <span class="op">{</span></span>
<span id="cb20-4"><a href="#cb20-4"></a> <span class="op">*</span>out<span class="op">++</span> <span class="op">=</span> item;</span>
<span id="cb20-5"><a href="#cb20-5"></a> <span class="op">}</span></span>
<span id="cb20-6"><a href="#cb20-6"></a> <span class="cf">return</span> out;</span>
<span id="cb20-7"><a href="#cb20-7"></a><span class="op">}</span></span></code></pre></div>
<p>This function operates on a range as its first argument, and an output iterator as its second argument. Usage is very simple:</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1"></a>std<span class="op">::</span>vector<span class="op"><</span><span class="dt">int</span><span class="op">></span> copies;</span>
<span id="cb21-2"><a href="#cb21-2"></a><span class="kw">auto</span> integers <span class="op">=</span> get_integers<span class="op">()</span>;</span>
<span id="cb21-3"><a href="#cb21-3"></a>copy<span class="op">(</span>integers, back_inserter<span class="op">(</span>copies<span class="op">))</span>;</span></code></pre></div>
<p>We can elide the extraneous <code class="sourceCode cpp">integers</code> variable to shrink the code:</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1"></a>std<span class="op">::</span>vector<span class="op"><</span><span class="dt">int</span><span class="op">></span> copies;</span>
<span id="cb22-2"><a href="#cb22-2"></a>copy<span class="op">(</span>get_integers<span class="op">()</span>, back_inserter<span class="op">(</span>copies<span class="op">))</span>;</span></code></pre></div>
<p>We may want to use pipeline syntax to perform the copy. Instead of using <code class="sourceCode cpp"><span class="op">|</span></code> for the pipeline style, we just use <code class="sourceCode cpp"><span class="op">|></span></code>. That would look like this:</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1"></a>std<span class="op">::</span>vector<span class="op"><</span><span class="dt">int</span><span class="op">></span> copies;</span>
<span id="cb23-2"><a href="#cb23-2"></a>get_integers<span class="op">()</span> <span class="op">|></span> copy<span class="op">(</span>back_inserter<span class="op">(</span>copies<span class="op">))</span>;</span></code></pre></div>
<h3 data-number="4.2.3" id="transform" data-number="4.2.3"><span class="header-section-number">4.2.3</span> <code class="sourceCode cpp">transform</code><a href="#transform" class="self-link"></a></h3>
<p>One of the most fundamental algorithms is <code class="sourceCode cpp">transform</code>. It applies a projection function to each element of the input range and yields the result of that projection.</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"><</span><span class="kw">typename</span> Range, <span class="kw">typename</span> Proj<span class="op">></span></span>
<span id="cb24-2"><a href="#cb24-2"></a><span class="kw">struct</span> __transform_view <span class="op">{</span></span>
<span id="cb24-3"><a href="#cb24-3"></a> <span class="co">// ...</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>
<span id="cb24-6"><a href="#cb24-6"></a><span class="kw">template</span> <span class="op"><</span><span class="kw">typename</span> Range, <span class="kw">typename</span> Proj, <span class="kw">typename</span> Out<span class="op">></span></span>
<span id="cb24-7"><a href="#cb24-7"></a><span class="kw">auto</span> transform<span class="op">(</span>Range<span class="op">&&</span> rng, Proj<span class="op">&&</span> fn<span class="op">)</span> <span class="op">{</span></span>
<span id="cb24-8"><a href="#cb24-8"></a> <span class="cf">return</span> __transform_view<span class="op">(</span>rng, fn<span class="op">)</span>;</span>
<span id="cb24-9"><a href="#cb24-9"></a><span class="op">}</span></span></code></pre></div>
<p>This algorithm is a <em>lazy</em> version of <code class="sourceCode cpp">transform</code>. It will apply the projection function to elements of <code class="sourceCode cpp">rng</code> as iterators on the <code class="sourceCode cpp">__transform_view</code> object are advanced.</p>
<p>Range algorithms compose. We can use this with <code class="sourceCode cpp">copy</code> to make a meaningful program:</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1"></a>copy<span class="op">(</span>transform<span class="op">(</span>get_words<span class="op">()</span>, make_uppercase<span class="op">)</span>, ostream_iterator<span class="op"><</span>string<span class="op">>{</span>cout, <span class="st">"</span><span class="sc">\n</span><span class="st">"</span><span class="op">})</span>;</span></code></pre></div>
<p>This code, of course, is inside-out from how evaluation is ordered. We can feed the result of <code class="sourceCode cpp">transform</code> into <code class="sourceCode cpp">copy</code> using <code class="sourceCode cpp"><span class="op">|></span></code>:</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1"></a>transform<span class="op">(</span>get_words<span class="op">()</span>, make_uppercase<span class="op">)</span></span>
<span id="cb26-2"><a href="#cb26-2"></a> <span class="op">|></span> copy<span class="op">(</span>ostream_iterator<span class="op"><</span>string<span class="op">>{</span>cout, <span class="st">"</span><span class="sc">\n</span><span class="st">"</span><span class="op">})</span>;</span></code></pre></div>
<p>And, without writing any additional support code, we can use <code class="sourceCode cpp"><span class="op">|></span></code> to feed <code class="sourceCode cpp">get_words</code> into <code class="sourceCode cpp">transform</code>:</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1"></a>get_words<span class="op">()</span></span>
<span id="cb27-2"><a href="#cb27-2"></a> <span class="op">|></span> transform<span class="op">(</span>make_uppercase<span class="op">)</span></span>
<span id="cb27-3"><a href="#cb27-3"></a> <span class="op">|></span> copy<span class="op">(</span>ostream_iterator<span class="op"><</span>string<span class="op">>{</span>cout, <span class="st">"</span><span class="sc">\n</span><span class="st">"</span><span class="op">})</span>;</span></code></pre></div>
<h3 data-number="4.2.4" id="a-new-algorithm-each_as" data-number="4.2.4"><span class="header-section-number">4.2.4</span> A New Algorithm: <code class="sourceCode cpp">each_as</code><a href="#a-new-algorithm-each_as" class="self-link"></a></h3>
<p>Ranges will be receiving a function template <code class="sourceCode cpp">to</code> that creates a concrete range from another range. A very primitive implementation of one overload might look like this:</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">template</span> <span class="op"><</span><span class="kw">typename</span> Container, <span class="kw">typename</span> Range<span class="op">></span></span>
<span id="cb28-2"><a href="#cb28-2"></a>Container to<span class="op">(</span><span class="kw">const</span> Range<span class="op">&</span> rng<span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-3"><a href="#cb28-3"></a> Container ret<span class="op">(</span>rng<span class="op">.</span>begin<span class="op">()</span>, rng<span class="op">.</span>end<span class="op">())</span>;</span>
<span id="cb28-4"><a href="#cb28-4"></a> <span class="cf">return</span> ret;</span>
<span id="cb28-5"><a href="#cb28-5"></a><span class="op">}</span></span></code></pre></div>
<p>This simply takes a range and uses it to fill a container with the iterator-pair constructor present on many container types. Usage looks like this:</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">auto</span> filenames <span class="op">=</span> get_strings<span class="op">()</span></span>
<span id="cb29-2"><a href="#cb29-2"></a> <span class="op">|></span> to<span class="op"><</span>vector<span class="op"><</span>filesystem<span class="op">::</span>path<span class="op">>>()</span></span>
<span id="cb29-3"><a href="#cb29-3"></a> <span class="op">|></span> transform<span class="op">(</span>get_filename<span class="op">)</span></span>
<span id="cb29-4"><a href="#cb29-4"></a> <span class="op">|></span> to<span class="op"><</span>vector<span class="op"><</span>string<span class="op">>>()</span>;</span></code></pre></div>
<p>However: The <code class="sourceCode cpp">to</code> algorithm, unlike <code class="sourceCode cpp">transform</code>, is <em>eager</em>. It consumes each element of the input immediately. This requires a concrete new container type that will eagerly allocate a buffer to hold the new objects. In the above snippet, all we are doing is obtaining the filenames of each file, and we do not actually care about the intermediate <code class="sourceCode cpp">std<span class="op">::</span>vector</code>.</p>
<p>Note: The above example is illustrative. There are other ways to perform the necessary transform.</p>
<p>What we may want it a new lazy algorithm that simply converts each range element to a new type as they pass through. How could we define such an algorithm?</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">template</span> <span class="op"><</span><span class="kw">typename</span> T, <span class="kw">typename</span> Range<span class="op">></span></span>
<span id="cb30-2"><a href="#cb30-2"></a><span class="kw">auto</span> each_as<span class="op">(</span>Range<span class="op">&&</span> rng<span class="op">)</span> <span class="op">{</span></span>
<span id="cb30-3"><a href="#cb30-3"></a> <span class="cf">return</span> rng <span class="op">|></span> transform<span class="op">([](</span><span class="kw">const</span> <span class="kw">auto</span><span class="op">&</span> item<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> T<span class="op">(</span>item<span class="op">)</span>; <span class="op">})</span>;</span>
<span id="cb30-4"><a href="#cb30-4"></a><span class="op">}</span></span></code></pre></div>
<p>With <code class="sourceCode cpp"><span class="op">|></span></code> at our disposal, there is no need to offer two overloads of <code class="sourceCode cpp">each_as</code> for the two styles. The above overload happily works with <code class="sourceCode cpp"><span class="op">|></span></code> pipeline style:</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">auto</span> filenames <span class="op">=</span> get_strings<span class="op">()</span></span>
<span id="cb31-2"><a href="#cb31-2"></a> <span class="op">|></span> each_as<span class="op"><</span>filesystem<span class="op">::</span>path<span class="op">>()</span></span>
<span id="cb31-3"><a href="#cb31-3"></a> <span class="op">|></span> transform<span class="op">(</span>get_filename<span class="op">)</span></span>
<span id="cb31-4"><a href="#cb31-4"></a> <span class="op">|></span> to<span class="op"><</span>vector<span class="op"><</span>string<span class="op">>>()</span>;</span></code></pre></div>
<p>Or non-pipeline style:</p>
<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">auto</span> filenames <span class="op">=</span></span>
<span id="cb32-2"><a href="#cb32-2"></a> each_as<span class="op"><</span>filesystem<span class="op">::</span>path<span class="op">>(</span>get_strings<span class="op">())</span></span>
<span id="cb32-3"><a href="#cb32-3"></a> <span class="op">|></span> transform<span class="op">(</span>get_filename<span class="op">)</span></span>
<span id="cb32-4"><a href="#cb32-4"></a> <span class="op">|></span> to<span class="op"><</span>vector<span class="op"><</span>string<span class="op">>>()</span>;</span></code></pre></div>
<h3 data-number="4.2.5" id="a-new-algorithm-copy_insertcopy_extend" data-number="4.2.5"><span class="header-section-number">4.2.5</span> A New Algorithm: <code class="sourceCode cpp">copy_insert</code>/<code class="sourceCode cpp">copy_extend</code><a href="#a-new-algorithm-copy_insertcopy_extend" class="self-link"></a></h3>
<p>A common operation is to collect the results of multiple computations into a single container. We can define two new algorithms:</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">template</span> <span class="op"><</span><span class="kw">typename</span> Range, <span class="kw">typename</span> Container, <span class="kw">typename</span> Iter<span class="op">></span></span>
<span id="cb33-2"><a href="#cb33-2"></a><span class="dt">void</span> copy_insert<span class="op">(</span>Range<span class="op">&&</span> rng, Container<span class="op">&</span> c, Iter it<span class="op">)</span> <span class="op">{</span></span>
<span id="cb33-3"><a href="#cb33-3"></a> rng <span class="op">|></span> copy<span class="op">(</span>inserter<span class="op">(</span>c, it<span class="op">))</span>;</span>
<span id="cb33-4"><a href="#cb33-4"></a><span class="op">}</span></span>
<span id="cb33-5"><a href="#cb33-5"></a></span>
<span id="cb33-6"><a href="#cb33-6"></a><span class="kw">template</span> <span class="op"><</span><span class="kw">typename</span> Range, <span class="kw">typename</span> Container<span class="op">></span></span>
<span id="cb33-7"><a href="#cb33-7"></a><span class="dt">void</span> copy_extend<span class="op">(</span>Range<span class="op">&&</span> rng, Container<span class="op">&</span> c<span class="op">)</span> <span class="op">{</span></span>
<span id="cb33-8"><a href="#cb33-8"></a> rng <span class="op">|></span> copy_insert<span class="op">(</span>c, c<span class="op">.</span>end<span class="op">())</span>;</span>
<span id="cb33-9"><a href="#cb33-9"></a><span class="op">}</span></span></code></pre></div>
<p>Again, we have <code class="sourceCode cpp"><span class="op">|></span></code> syntax using normal functions and no special return types or expression templates.</p>
<p>Using them is very simple:</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="co">// We may use pipeline style:</span></span>
<span id="cb34-2"><a href="#cb34-2"></a><span class="dt">void</span> collect_filenames<span class="op">(</span>filesystem<span class="op">::</span>path dirpath, vector<span class="op"><</span>string<span class="op">>&</span> fnames<span class="op">)</span> <span class="op">{</span></span>
<span id="cb34-3"><a href="#cb34-3"></a> filesystem<span class="op">::</span>directory_iterator<span class="op">{</span>dirpath<span class="op">}</span></span>
<span id="cb34-4"><a href="#cb34-4"></a> <span class="op">|></span> copy_extend<span class="op">(</span>fnames<span class="op">)</span>;</span>
<span id="cb34-5"><a href="#cb34-5"></a><span class="op">}</span></span>
<span id="cb34-6"><a href="#cb34-6"></a></span>
<span id="cb34-7"><a href="#cb34-7"></a><span class="co">// Or we may use classical style:</span></span>
<span id="cb34-8"><a href="#cb34-8"></a><span class="dt">void</span> collect_filenames<span class="op">(</span>filesystem<span class="op">::</span>path dirpath, vector<span class="op"><</span>string<span class="op">>&</span> fnames<span class="op">)</span> <span class="op">{</span></span>
<span id="cb34-9"><a href="#cb34-9"></a> copy_extend<span class="op">(</span></span>
<span id="cb34-10"><a href="#cb34-10"></a> filesystem<span class="op">::</span>directory_iterator<span class="op">{</span>dirpath<span class="op">}</span>,</span>
<span id="cb34-11"><a href="#cb34-11"></a> fnames</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 class="op">}</span></span></code></pre></div>
<h3 data-number="4.2.6" id="not-a-new-algorithm-any_of" data-number="4.2.6"><span class="header-section-number">4.2.6</span> Not A New Algorithm: <code class="sourceCode cpp">any_of</code><a href="#not-a-new-algorithm-any_of" class="self-link"></a></h3>
<p>Of course, we can go back to Conor’s example and provide a complete implementation of it:</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1"></a><span class="kw">auto</span> dangerous_teams<span class="op">(</span>std<span class="op">::</span>string <span class="kw">const</span><span class="op">&</span> s<span class="op">)</span> <span class="op">-></span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb35-2"><a href="#cb35-2"></a> <span class="cf">return</span> s</span>
<span id="cb35-3"><a href="#cb35-3"></a> <span class="op">|></span> views<span class="op">::</span>group_by<span class="op">(</span>std<span class="op">::</span>equal_to<span class="op">{})</span></span>
<span id="cb35-4"><a href="#cb35-4"></a> <span class="op">|></span> views<span class="op">::</span>transform<span class="op">(</span>ranges<span class="op">::</span>distance<span class="op">)</span></span>
<span id="cb35-5"><a href="#cb35-5"></a> <span class="op">|></span> ranges<span class="op">::</span>any_of<span class="op">([](</span>std<span class="op">::</span><span class="dt">size_t</span> s<span class="op">){</span></span>
<span id="cb35-6"><a href="#cb35-6"></a> <span class="cf">return</span> s <span class="op">>=</span> <span class="dv">7</span>;</span>
<span id="cb35-7"><a href="#cb35-7"></a> <span class="op">})</span>;</span>
<span id="cb35-8"><a href="#cb35-8"></a><span class="op">}</span></span></code></pre></div>
<p>It is worth repeatedly stressing that this does <em>not</em> require any new overloads of <code class="sourceCode cpp">any_of</code> to allow this usage. The above function evaluates exactly as:</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1"></a><span class="kw">auto</span> dangerous_teams_rewritten<span class="op">(</span>std<span class="op">::</span>string <span class="kw">const</span><span class="op">&</span> s<span class="op">)</span> <span class="op">-></span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb36-2"><a href="#cb36-2"></a> <span class="cf">return</span> ranges<span class="op">::</span>any_of<span class="op">(</span></span>
<span id="cb36-3"><a href="#cb36-3"></a> ranges<span class="op">::</span>transform<span class="op">(</span></span>
<span id="cb36-4"><a href="#cb36-4"></a> ranges<span class="op">::</span>group_by<span class="op">(</span></span>
<span id="cb36-5"><a href="#cb36-5"></a> s,</span>
<span id="cb36-6"><a href="#cb36-6"></a> std<span class="op">::</span>equal_to<span class="op">{})</span>,</span>
<span id="cb36-7"><a href="#cb36-7"></a> ranges<span class="op">::</span>distance<span class="op">)</span>,</span>
<span id="cb36-8"><a href="#cb36-8"></a> <span class="op">[](</span>std<span class="op">::</span><span class="dt">size_t</span> s<span class="op">){</span></span>
<span id="cb36-9"><a href="#cb36-9"></a> <span class="cf">return</span> s <span class="op">>=</span> <span class="dv">7</span>;</span>
<span id="cb36-10"><a href="#cb36-10"></a> <span class="op">})</span>;</span>
<span id="cb36-11"><a href="#cb36-11"></a><span class="op">}</span></span></code></pre></div>
<p>This rewrite isn’t exactly readable, but that’s not the point - nobody has to read it. Only the compiler has to know how to evaluate these calls, and it has no problem at all figuring out the right thing to do.</p>
<h3 data-number="4.2.7" id="async-examples" data-number="4.2.7"><span class="header-section-number">4.2.7</span> Async Examples<a href="#async-examples" class="self-link"></a></h3>
<p>Ranges isn’t the only subset of C++ that would benefit from the existence of a pipeline rewrite operator. At CppCon 2019, Eric Niebler and David Hollman presented <a href="https://www.youtube.com/watch?v=tF-Nz4aRWAM">A Unifying Abstraction for Async in C++</a>, illustrating the executors work that’s been ongoing for a few years now. They build up to the following example:</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb37-2"><a href="#cb37-2"></a> <span class="kw">auto</span> f <span class="op">=</span> async_algo<span class="op">(</span>new_thread<span class="op">())</span>;</span>
<span id="cb37-3"><a href="#cb37-3"></a> <span class="kw">auto</span> f2 <span class="op">=</span> then<span class="op">(</span>f, <span class="op">[](</span><span class="dt">int</span> i<span class="op">){</span></span>
<span id="cb37-4"><a href="#cb37-4"></a> <span class="cf">return</span> i <span class="op">+</span> rand<span class="op">()</span>;</span>
<span id="cb37-5"><a href="#cb37-5"></a> <span class="op">})</span>;</span>
<span id="cb37-6"><a href="#cb37-6"></a> printf<span class="op">(</span><span class="st">"</span><span class="sc">%d\n</span><span class="st">"</span>, sync_wait<span class="op"><</span><span class="dt">int</span><span class="op">>(</span>f2<span class="op">))</span>;</span>
<span id="cb37-7"><a href="#cb37-7"></a><span class="op">}</span></span></code></pre></div>
<p>With this proposal, this could be written (with zero additional library work on anyone’s part) as:</p>
<div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1"></a><span class="dt">int</span> main<span class="op">()</span> <span class="op">{</span></span>
<span id="cb38-2"><a href="#cb38-2"></a> <span class="kw">auto</span> result <span class="op">=</span></span>
<span id="cb38-3"><a href="#cb38-3"></a> new_thread<span class="op">()</span></span>
<span id="cb38-4"><a href="#cb38-4"></a> <span class="op">|></span> async_algo<span class="op">()</span></span>
<span id="cb38-5"><a href="#cb38-5"></a> <span class="op">|></span> then<span class="op">([](</span><span class="dt">int</span> i<span class="op">){</span> <span class="cf">return</span> i <span class="op">+</span> rand<span class="op">()</span>; <span class="op">})</span></span>
<span id="cb38-6"><a href="#cb38-6"></a> <span class="op">|></span> sync_wait<span class="op"><</span><span class="dt">int</span><span class="op">>()</span>;</span>
<span id="cb38-7"><a href="#cb38-7"></a> printf<span class="op">(</span><span class="st">"</span><span class="sc">%d\n</span><span class="st">"</span>, result<span class="op">)</span>;</span>