-
Notifications
You must be signed in to change notification settings - Fork 22
/
p2561r1.html
1292 lines (1284 loc) · 138 KB
/
p2561r1.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="2022-10-11" />
<title>An error propagation 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">An error propagation operator</h1>
<table style="border:none;float:right">
<tr>
<td>Document #:</td>
<td>P2561R1</td>
</tr>
<tr>
<td>Date:</td>
<td>2022-10-11</td>
</tr>
<tr>
<td style="vertical-align:top">Project:</td>
<td>Programming Language C++</td>
</tr>
<tr>
<td style="vertical-align:top">Audience:</td>
<td>
EWG<br>
</td>
</tr>
<tr>
<td style="vertical-align:top">Reply-to:</td>
<td>
Barry Revzin<br><<a href="mailto:[email protected]" class="email">[email protected]</a>><br>
</td>
</tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#revision-history"><span class="toc-section-number">1</span> Revision History<span></span></a></li>
<li><a href="#preface"><span class="toc-section-number">2</span> Preface<span></span></a></li>
<li><a href="#introduction"><span class="toc-section-number">3</span> Introduction<span></span></a></li>
<li><a href="#an-automatic-propagation-operator"><span class="toc-section-number">4</span> An automatic propagation operator<span></span></a>
<ul>
<li><a href="#syntax-for-c"><span class="toc-section-number">4.1</span> Syntax for C++<span></span></a>
<ul>
<li><a href="#why-not-try"><span class="toc-section-number">4.1.1</span> Why not <code class="sourceCode cpp"><span class="cf">try</span></code>?<span></span></a></li>
<li><a href="#why-not-prefix"><span class="toc-section-number">4.1.2</span> Why not prefix?<span></span></a></li>
<li><a href="#in-other-languages"><span class="toc-section-number">4.1.3</span> <code class="sourceCode cpp"><span class="op">??</span></code> in other languages<span></span></a></li>
</ul></li>
<li><a href="#semantics"><span class="toc-section-number">4.2</span> Semantics<span></span></a>
<ul>
<li><a href="#lifetime"><span class="toc-section-number">4.2.1</span> Lifetime<span></span></a></li>
<li><a href="#decltype"><span class="toc-section-number">4.2.2</span> <code class="sourceCode cpp"><span class="kw">decltype</span></code><span></span></a></li>
<li><a href="#requires"><span class="toc-section-number">4.2.3</span> <code class="sourceCode cpp"><span class="kw">requires</span></code><span></span></a></li>
<li><a href="#short-circuiting-fold"><span class="toc-section-number">4.2.4</span> Short-circuiting fold<span></span></a></li>
<li><a href="#range-of-expected-to-expected-of-range"><span class="toc-section-number">4.2.5</span> Range of <code class="sourceCode cpp">expected</code> to <code class="sourceCode cpp">expected</code> of Range<span></span></a></li>
<li><a href="#naming"><span class="toc-section-number">4.2.6</span> Naming<span></span></a></li>
</ul></li>
<li><a href="#potential-directions-to-go-from-here"><span class="toc-section-number">4.3</span> Potential directions to go from here<span></span></a>
<ul>
<li><a href="#error-continuations"><span class="toc-section-number">4.3.1</span> Error continuations<span></span></a></li>
<li><a href="#not-propagating-errors"><span class="toc-section-number">4.3.2</span> Not propagating errors<span></span></a></li>
</ul></li>
</ul></li>
<li><a href="#bibliography"><span class="toc-section-number">5</span> References<span></span></a></li>
</ul>
</div>
<h1 data-number="1" style="border-bottom:1px solid #cccccc" id="revision-history"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>The title of <span class="citation" data-cites="P2561R0">[<a href="#ref-P2561R0" role="doc-biblioref">P2561R0</a>]</span> was <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">??</span></code>, but isn’t actually proposing that token, so it’s not the best title. Likewise, <code class="sourceCode cpp">try_traits</code> is a bad name for the collection of functionality for the same reason that the paper described <code class="sourceCode cpp"><span class="cf">try</span></code> as being a bad spelling for the operator. <code class="sourceCode cpp">is_ok</code> has been renamed to <code class="sourceCode cpp">has_value</code>, since that’s actually what we name that facility everywhere. A few other details added in addition to the two renames.</p>
<h1 data-number="2" style="border-bottom:1px solid #cccccc" id="preface"><span class="header-section-number">2</span> Preface<a href="#preface" class="self-link"></a></h1>
<p>It is important to clarify a few things up front. It is not the position of this paper that exceptions are bad. Or that exceptions are good. It is not the goal of this paper to convince you to start using exceptions, nor is it to convince you to stop using exceptions.</p>
<p>This paper simply recognizes that there are many code bases (or parts thereof) that do not use exceptions and probably will not in the future. That could be for performance or space reasons. It could be because exceptions are unsupported on a particular platform. It could be for code understandability reasons. Regardless, some code bases do not use exceptions. Moreover, some problems are not solved well by exceptions – even in code bases that otherwise use them to solve problems that they are more tailored to solve.</p>
<p>The problem is, C++ does not currently have a good story for error handling without exceptions. We’re moving away from returning bool or error codes in favor of solutions like <code class="sourceCode cpp">std<span class="op">::</span>expected</code> (<span class="citation" data-cites="P0323R12">[<a href="#ref-P0323R12" role="doc-biblioref">P0323R12</a>]</span>), but the ergonomics of such types are not there yet. Bad ergonomics leads to code that is clunkier than it needs to be, harder to follow, and, significantly and ironically, error-prone.</p>
<p>We should try to improve such uses too.</p>
<h1 data-number="3" style="border-bottom:1px solid #cccccc" id="introduction"><span class="header-section-number">3</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>Let’s start with a fairly small example of a series of functions that can generate errors, but don’t themselves handle them - they just need to propagate them up. With exceptions, this might look like:</p>
<blockquote>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">auto</span> foo<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> <span class="dt">int</span>; <span class="co">// might throw an E</span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">auto</span> bar<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> <span class="dt">int</span>; <span class="co">// might throw an E</span></span>
<span id="cb1-3"><a href="#cb1-3"></a></span>
<span id="cb1-4"><a href="#cb1-4"></a><span class="kw">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>string <span class="op">{</span></span>
<span id="cb1-5"><a href="#cb1-5"></a> <span class="dt">int</span> f <span class="op">=</span> foo<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb1-6"><a href="#cb1-6"></a> <span class="dt">int</span> b <span class="op">=</span> bar<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb1-7"><a href="#cb1-7"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, f, b<span class="op">)</span>;</span>
<span id="cb1-8"><a href="#cb1-8"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>There’s a lot to like about exceptions. One nice advantage is the zero syntactic overhead necessary for propagating errors. Errors just propagate. You don’t even have to know which functions can fail.</p>
<p>We don’t even need to declare variables to hold the results of <code class="sourceCode cpp">foo</code> and <code class="sourceCode cpp">bar</code>, we can even use those expressions inline, knowing that we’ll only call <code class="sourceCode cpp">format</code> if neither function throws an exception:</p>
<blockquote>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">auto</span> foo<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> <span class="dt">int</span>; <span class="co">// might throw an E</span></span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="kw">auto</span> bar<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> <span class="dt">int</span>; <span class="co">// might throw an E</span></span>
<span id="cb2-3"><a href="#cb2-3"></a></span>
<span id="cb2-4"><a href="#cb2-4"></a><span class="kw">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>string <span class="op">{</span></span>
<span id="cb2-5"><a href="#cb2-5"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, foo<span class="op">(</span>i<span class="op">)</span>, bar<span class="op">(</span>i<span class="op">))</span>;</span>
<span id="cb2-6"><a href="#cb2-6"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>But with the newly adopted <code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op"><</span>T, E<span class="op">></span></code>, it’s not quite so nice:</p>
<blockquote>
<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">auto</span> foo<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span><span class="dt">int</span>, E<span class="op">></span>;</span>
<span id="cb3-2"><a href="#cb3-2"></a><span class="kw">auto</span> bar<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span><span class="dt">int</span>, E<span class="op">></span>;</span>
<span id="cb3-3"><a href="#cb3-3"></a></span>
<span id="cb3-4"><a href="#cb3-4"></a><span class="kw">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>std<span class="op">::</span>string, E<span class="op">></span></span>
<span id="cb3-5"><a href="#cb3-5"></a><span class="op">{</span></span>
<span id="cb3-6"><a href="#cb3-6"></a> <span class="kw">auto</span> f <span class="op">=</span> foo<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb3-7"><a href="#cb3-7"></a> <span class="cf">if</span> <span class="op">(</span><span class="kw">not</span> f<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-8"><a href="#cb3-8"></a> <span class="cf">return</span> std<span class="op">::</span>unexpected<span class="op">(</span>f<span class="op">.</span>error<span class="op">())</span>;</span>
<span id="cb3-9"><a href="#cb3-9"></a> <span class="op">}</span></span>
<span id="cb3-10"><a href="#cb3-10"></a></span>
<span id="cb3-11"><a href="#cb3-11"></a> <span class="kw">auto</span> b <span class="op">=</span> bar<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb3-12"><a href="#cb3-12"></a> <span class="cf">if</span> <span class="op">(</span><span class="kw">not</span> b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb3-13"><a href="#cb3-13"></a> <span class="cf">return</span> std<span class="op">::</span>unexpected<span class="op">(</span>b<span class="op">.</span>error<span class="op">())</span>;</span>
<span id="cb3-14"><a href="#cb3-14"></a> <span class="op">}</span></span>
<span id="cb3-15"><a href="#cb3-15"></a></span>
<span id="cb3-16"><a href="#cb3-16"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, <span class="op">*</span>f, <span class="op">*</span>b<span class="op">)</span>;</span>
<span id="cb3-17"><a href="#cb3-17"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This is significantly longer and more tedious because we have to do manual error propagation. This manual error propagation is most of the code in this short example, and is bad not just because of the lengthy boilerplate, but also because:</p>
<ul>
<li>we’re giving a name, <code class="sourceCode cpp">f</code>, to the <code class="sourceCode cpp">expected</code> object, not the success value. The error case is typically immediately handled, but the value case could be used multiple times and now has to be used as <code class="sourceCode cpp"><span class="op">*</span>f</code> (which is pretty weird for something that is decidedly not a pointer or even, unlike iterators, a generalization of pointer) or <code class="sourceCode cpp">f<span class="op">.</span>value<span class="op">()</span></code></li>
<li>the “nice” syntax for propagation - <code class="sourceCode cpp"><span class="cf">return</span> std<span class="op">::</span>unexpected<span class="op">(</span>e<span class="op">)</span></code> - is inefficient - if <code class="sourceCode cpp">E</code> is something more involved than <code class="sourceCode cpp">std<span class="op">::</span>error_code</code>, we really should <code class="sourceCode cpp">std<span class="op">::</span>move<span class="op">(</span>f<span class="op">).</span>error<span class="op">()</span></code> into that. And even then, we’re moving the error twice when we optimally could move it just once. The ideal would be: <code class="sourceCode cpp"><span class="cf">return</span> <span class="op">{</span>std<span class="op">::</span>unexpect, std<span class="op">::</span>move<span class="op">(</span>f<span class="op">).</span>error<span class="op">()}</span>;</code>, which is something I don’t expect a lot of people to actually write.</li>
</ul>
<p>In an effort to avoid… that… many libraries or code bases that use this sort approach to error handling provide a macro, which usually looks like this (<a href="https://www.boost.org/doc/libs/1_75_0/libs/leaf/doc/html/index.html#BOOST_LEAF_ASSIGN">Boost.LEAF</a>, <a href="https://www.boost.org/doc/libs/develop/libs/outcome/doc/html/reference/macros/try.html">Boost.Outcome</a>, <a href="https://github.com/google/mediapipe/blob/master/mediapipe/framework/deps/status_macros.h">mediapipe</a>, <a href="https://github.com/SerenityOS/serenity/blob/50642f85ac547a3caee353affcb08872cac49456/Documentation/Patterns.md#try-error-handling">SerenityOS</a>, etc. Although not all do, neither <code class="sourceCode cpp">folly</code>’s <code class="sourceCode cpp">fb<span class="op">::</span>Expected</code> nor <code class="sourceCode cpp">tl<span class="op">::</span>expected</code> nor <code class="sourceCode cpp">llvm<span class="op">::</span>Expected</code> provide such):</p>
<blockquote>
<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">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>std<span class="op">::</span>string, E<span class="op">></span></span>
<span id="cb4-2"><a href="#cb4-2"></a><span class="op">{</span></span>
<span id="cb4-3"><a href="#cb4-3"></a> SOMETHING_TRY<span class="op">(</span><span class="dt">int</span> f, foo<span class="op">(</span>i<span class="op">))</span>;</span>
<span id="cb4-4"><a href="#cb4-4"></a> SOMETHING_TRY<span class="op">(</span><span class="dt">int</span> b, bar<span class="op">(</span>i<span class="op">))</span>;</span>
<span id="cb4-5"><a href="#cb4-5"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, f, b<span class="op">)</span>;</span>
<span id="cb4-6"><a href="#cb4-6"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>Which avoids all those problems, though each such library type will have its own corresponding macro. Also these <code class="sourceCode cpp">TRY</code> macros (not all of them have <code class="sourceCode cpp">TRY</code> in the name) need to be written on their own line, since they are declarations - thus the one-line version of <code class="sourceCode cpp">strcat</code> in the exception version isn’t possible.</p>
<p>Some more adventurous macros take advantage of the statement-expression extension, which would allow you to do this:</p>
<blockquote>
<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> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>std<span class="op">::</span>string, E<span class="op">></span></span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3"></a> <span class="dt">int</span> f <span class="op">=</span> SOMETHING_TRY_EXPR<span class="op">(</span>foo<span class="op">(</span>i<span class="op">))</span>;</span>
<span id="cb5-4"><a href="#cb5-4"></a> <span class="dt">int</span> b <span class="op">=</span> SOMETHING_TRY_EXPR<span class="op">(</span>bar<span class="op">(</span>i<span class="op">))</span>;</span>
<span id="cb5-5"><a href="#cb5-5"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, f, b<span class="op">)</span>;</span>
<span id="cb5-6"><a href="#cb5-6"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>And thus also write both macros inline. But this relies on compiler extensions, and this particular extension isn’t quite as efficient as it could be - and in particular it doesn’t move when it should.</p>
<p>Both macros also suffer when the function in question returns <code class="sourceCode cpp">expected<span class="op"><</span><span class="dt">void</span>, E<span class="op">></span></code>, since you cannot declare (or assign to) a variable to hold that value, so the macro needs to emit different code to handle this case (<a href="https://www.boost.org/doc/libs/1_75_0/libs/leaf/doc/html/index.html#BOOST_LEAF_CHECK">Boost.LEAF</a>, <a href="https://www.boost.org/doc/libs/develop/libs/outcome/doc/html/reference/macros/tryv.html">Boost.Outcome</a>,<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a> etc.)</p>
<p>To that end, in search for nice syntax, some people turn to coroutines:</p>
<blockquote>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1"></a><span class="kw">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>std<span class="op">::</span>string, E<span class="op">></span></span>
<span id="cb6-2"><a href="#cb6-2"></a><span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3"></a> <span class="dt">int</span> f <span class="op">=</span> <span class="kw">co_await</span> foo<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb6-4"><a href="#cb6-4"></a> <span class="dt">int</span> b <span class="op">=</span> <span class="kw">co_await</span> bar<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb6-5"><a href="#cb6-5"></a> <span class="kw">co_return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, f, b<span class="op">)</span>;</span>
<span id="cb6-6"><a href="#cb6-6"></a></span>
<span id="cb6-7"><a href="#cb6-7"></a> <span class="co">// ... or</span></span>
<span id="cb6-8"><a href="#cb6-8"></a> <span class="kw">co_return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, <span class="kw">co_await</span> foo<span class="op">(</span>i<span class="op">)</span>, <span class="kw">co_await</span> bar<span class="op">(</span>i<span class="op">))</span>;</span>
<span id="cb6-9"><a href="#cb6-9"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>This can be made to work in a fully-conformant way (at the syntactic cost of having to now write <code class="sourceCode cpp"><span class="kw">co_return</span></code>), and we can use the same syntax for both the <code class="sourceCode cpp"><span class="dt">void</span></code> and non-<code class="sourceCode cpp"><span class="dt">void</span></code> cases.</p>
<p>However, currently even the simple cases allocate which make this approach unusuable in many production contexts. The coroutine machinery also isn’t fully composable and runs into problems once you start doing something like <code class="sourceCode cpp">optional<span class="op"><</span>expected<span class="op"><</span>T, E<span class="op">>></span></code> (or vice versa) or <code class="sourceCode cpp">task<span class="op"><</span>optional<span class="op"><</span>T<span class="op">>></span></code>.</p>
<p>Which means the best-case today still involves <del>being jealous of exceptions</del> macros.</p>
<h1 data-number="4" style="border-bottom:1px solid #cccccc" id="an-automatic-propagation-operator"><span class="header-section-number">4</span> An automatic propagation operator<a href="#an-automatic-propagation-operator" class="self-link"></a></h1>
<p>Let’s talk about Rust.</p>
<p>Rust’s primary form of error handling is a sum type named <code class="sourceCode cpp">Result<span class="op"><</span>T, E<span class="op">></span></code>. Taking our original example here and rewriting it in Rust (as one does) would look like this:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Rust</strong>
</div></th>
<th><div style="text-align:center">
<strong>C++</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb1"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">fn</span> strcat(i<span class="op">:</span> <span class="dt">i32</span>) <span class="op">-></span> <span class="dt">Result</span><span class="op"><</span><span class="dt">String</span><span class="op">,</span> E<span class="op">></span> <span class="op">{</span></span>
<span id="cb1-2"><a href="#cb1-2"></a> <span class="kw">let</span> f <span class="op">=</span> <span class="kw">match</span> foo(i) <span class="op">{</span></span>
<span id="cb1-3"><a href="#cb1-3"></a> <span class="cn">Ok</span>(i) <span class="op">=></span> i<span class="op">,</span></span>
<span id="cb1-4"><a href="#cb1-4"></a> <span class="cn">Err</span>(e) <span class="op">=></span> <span class="kw">return</span> <span class="cn">Err</span>(e)<span class="op">,</span></span>
<span id="cb1-5"><a href="#cb1-5"></a> <span class="op">};</span></span>
<span id="cb1-6"><a href="#cb1-6"></a></span>
<span id="cb1-7"><a href="#cb1-7"></a> <span class="kw">let</span> b <span class="op">=</span> <span class="kw">match</span> bar(i) <span class="op">{</span></span>
<span id="cb1-8"><a href="#cb1-8"></a> <span class="cn">Ok</span>(i) <span class="op">=></span> i<span class="op">,</span></span>
<span id="cb1-9"><a href="#cb1-9"></a> <span class="cn">Err</span>(e) <span class="op">=></span> <span class="kw">return</span> <span class="cn">Err</span>(e)<span class="op">,</span></span>
<span id="cb1-10"><a href="#cb1-10"></a> <span class="op">}</span></span>
<span id="cb1-11"><a href="#cb1-11"></a></span>
<span id="cb1-12"><a href="#cb1-12"></a> <span class="cn">Ok</span>(<span class="pp">format!</span>(<span class="st">"{}{}"</span><span class="op">,</span> f<span class="op">,</span> b))</span>
<span id="cb1-13"><a href="#cb1-13"></a><span class="op">}</span></span></code></pre></div></td>
<td><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">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>std<span class="op">::</span>string, E<span class="op">></span> <span class="op">{</span></span>
<span id="cb7-2"><a href="#cb7-2"></a> <span class="kw">auto</span> f <span class="op">=</span> foo<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb7-3"><a href="#cb7-3"></a> <span class="cf">if</span> <span class="op">(</span><span class="kw">not</span> f<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-4"><a href="#cb7-4"></a> <span class="cf">return</span> std<span class="op">::</span>unexpected<span class="op">(</span>f<span class="op">.</span>error<span class="op">())</span>;</span>
<span id="cb7-5"><a href="#cb7-5"></a> <span class="op">}</span></span>
<span id="cb7-6"><a href="#cb7-6"></a></span>
<span id="cb7-7"><a href="#cb7-7"></a> <span class="kw">auto</span> b <span class="op">=</span> bar<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb7-8"><a href="#cb7-8"></a> <span class="cf">if</span> <span class="op">(</span><span class="kw">not</span> b<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-9"><a href="#cb7-9"></a> <span class="cf">return</span> std<span class="op">::</span>unexpected<span class="op">(</span>b<span class="op">.</span>error<span class="op">())</span>;</span>
<span id="cb7-10"><a href="#cb7-10"></a> <span class="op">}</span></span>
<span id="cb7-11"><a href="#cb7-11"></a></span>
<span id="cb7-12"><a href="#cb7-12"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, <span class="op">*</span>f, <span class="op">*</span>b<span class="op">)</span>;</span>
<span id="cb7-13"><a href="#cb7-13"></a><span class="op">}</span></span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>This fully manual version is already better than the C++ version due to pattern matching’s ability to just give a name to the thing we care about (the value) and avoid giving a name to the thing we don’t care about (the <code class="sourceCode cpp">Result</code> object).</p>
<p>But this isn’t the way you do things in Rust.</p>
<p>Originally, there was a <a href="https://doc.rust-lang.org/std/macro.try.html"><code class="sourceCode cpp"><span class="cf">try</span><span class="op">!</span></code> macro</a> which was defined mostly as that <code class="sourceCode cpp">match</code> expression I have above. But then this got generalized into <code class="sourceCode cpp"><span class="kw">operator</span><span class="op">?</span></code>, whose behavior is driven by the <a href="https://doc.rust-lang.org/std/ops/trait.Try.html"><code class="sourceCode cpp">Try</code> trait</a> (originally there was <a href="https://rust-lang.github.io/rfcs/1859-try-trait.html">try-v1</a>, now this is <a href="https://rust-lang.github.io/rfcs/3058-try-trait-v2.html">try-v2</a>). That allows simply writing this:</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Rust</strong>
</div></th>
<th><div style="text-align:center">
<strong>C++ with exceptions</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb2"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">fn</span> strcat(i<span class="op">:</span> <span class="dt">i32</span>) <span class="op">-></span> <span class="dt">Result</span><span class="op"><</span><span class="dt">String</span><span class="op">,</span> E<span class="op">></span> <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2"></a> <span class="kw">let</span> f <span class="op">=</span> foo(i)<span class="op">?;</span></span>
<span id="cb2-3"><a href="#cb2-3"></a> <span class="kw">let</span> b <span class="op">=</span> bar(i)<span class="op">?;</span></span>
<span id="cb2-4"><a href="#cb2-4"></a> <span class="cn">Ok</span>(<span class="pp">format!</span>(<span class="st">"{}{}"</span><span class="op">,</span> f<span class="op">,</span> b))</span>
<span id="cb2-5"><a href="#cb2-5"></a></span>
<span id="cb2-6"><a href="#cb2-6"></a> <span class="co">// ... or simply ...</span></span>
<span id="cb2-7"><a href="#cb2-7"></a> <span class="cn">Ok</span>(<span class="pp">format!</span>(<span class="st">"{}{}"</span><span class="op">,</span> foo(i)<span class="op">?,</span> bar(i)<span class="op">?</span>))</span>
<span id="cb2-8"><a href="#cb2-8"></a><span class="op">}</span></span></code></pre></div></td>
<td><div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1"></a><span class="kw">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>string <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2"></a> <span class="dt">int</span> f <span class="op">=</span> foo<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb8-3"><a href="#cb8-3"></a> <span class="dt">int</span> b <span class="op">=</span> bar<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb8-4"><a href="#cb8-4"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, f, b<span class="op">)</span>;</span>
<span id="cb8-5"><a href="#cb8-5"></a></span>
<span id="cb8-6"><a href="#cb8-6"></a> <span class="co">// ... or simply ...</span></span>
<span id="cb8-7"><a href="#cb8-7"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, foo<span class="op">(</span>i<span class="op">)</span>, bar<span class="op">(</span>i<span class="op">))</span>;</span>
<span id="cb8-8"><a href="#cb8-8"></a><span class="op">}</span></span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>Now, Rust still has manual error propagation, but it’s the minimal possible syntactic overhead: one character per expression.</p>
<p>Importantly, one character per expression is still actually an enormous amount more overhead than zero characters per expression, since that implies that you cannot have error-neutral functions - they have to manually propagate errors too.</p>
<p>But to those people who write code using types like <code class="sourceCode cpp">std<span class="op">::</span>expected</code> today, who may use the kinds of macros I showed earlier or foray into coroutines, this is kind of a dream?</p>
<h2 data-number="4.1" id="syntax-for-c"><span class="header-section-number">4.1</span> Syntax for C++<a href="#syntax-for-c" class="self-link"></a></h2>
<p>Before diving too much into semantics, let’s just start by syntax. Unfortunately, C++ cannot simply grab the Rust syntax of a postfix <code class="sourceCode cpp"><span class="op">?</span></code> here, because we also have the conditional operator <code class="sourceCode cpp"><span class="op">?:</span></code>, with which it can be ambiguous:</p>
<blockquote>
<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> res <span class="op">=</span> a <span class="op">?</span> <span class="op">*</span> b <span class="op">?</span> <span class="op">*</span> c <span class="op">:</span> d;</span></code></pre></div>
</blockquote>
<p>That could be parsed two ways:</p>
<blockquote>
<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> res1 <span class="op">=</span> a <span class="op">?</span> <span class="op">(*(</span>b<span class="op">?)</span> <span class="op">*</span> c<span class="op">)</span> <span class="op">:</span> d;</span>
<span id="cb10-2"><a href="#cb10-2"></a><span class="kw">auto</span> res2 <span class="op">=</span> <span class="op">((</span>a<span class="op">?)</span> <span class="op">*</span> b<span class="op">)</span> <span class="op">?</span> <span class="op">(*</span>c<span class="op">)</span> <span class="op">:</span> d;</span></code></pre></div>
</blockquote>
<p>What if you assume that a <code class="sourceCode cpp"><span class="op">?</span></code> is a conditional operator and try to parse that until it fails, then back up and try again to parse a postfix <code class="sourceCode cpp"><span class="op">?</span></code> operator? Is that really a viable strategy? If we assume both <code class="sourceCode cpp"><span class="op">?</span></code>s are the beginning of a conditional, then that will eventually fail since we hit a <code class="sourceCode cpp">;</code> before a second <code class="sourceCode cpp"><span class="op">:</span></code> - but it’s the outer <code class="sourceCode cpp"><span class="op">?</span></code> that failed, not the inner - do we retry the inner first (which would lead to the <code class="sourceCode cpp">res1</code> parse eventually) or the outer first (which would lead to the <code class="sourceCode cpp">res2</code> one)?</p>
<p>Maybe this is doable with parsing heroics, but at some point I have to ask if it’s worth it.</p>
<p>Another reason that a single <code class="sourceCode cpp"><span class="op">?</span></code> might not be a good idea, even if it were possible to parse, would be <a href="#error-continuations">optional chaining</a>. With that facility, if <code class="sourceCode cpp">o</code> were an <code class="sourceCode cpp">optional<span class="op"><</span>string<span class="op">></span></code>, <code class="sourceCode cpp">o<span class="op">?.</span>size<span class="op">()</span></code> would be an <code class="sourceCode cpp">optional<span class="op"><</span><span class="dt">size_t</span><span class="op">></span></code> (that is either engaged with the original string’s size, or empty). But if <code class="sourceCode cpp">o<span class="op">?</span></code> propagated the error, then <code class="sourceCode cpp">o<span class="op">?.</span>size<span class="op">()</span></code> would itself be a valid expression that is a <code class="sourceCode cpp"><span class="dt">size_t</span></code> (the string’s size, and if we didn’t have a string we would have returned). So if we want to support error continuations, we’d need distinct syntax for these cases.</p>
<p>This paper proposes an alternative token that isn’t valid in C++ today, requires no parsing heroics, and doesn’t conflict with a potential optional chaining operator: <code class="sourceCode cpp"><span class="op">??</span></code></p>
<p>This is only one character longer, and just as questioning. It’s easily unambiguous by virtue of not even being a valid token sequence today. But it’s worth commenting further on this choice of syntax.</p>
<h3 data-number="4.1.1" id="why-not-try"><span class="header-section-number">4.1.1</span> Why not <code class="sourceCode cpp"><span class="cf">try</span></code>?<a href="#why-not-try" class="self-link"></a></h3>
<p>For those libraries that provide this operation as a macro, the name is usually <code class="sourceCode cpp">TRY</code> and <span class="citation" data-cites="P0779R0">[<a href="#ref-P0779R0" role="doc-biblioref">P0779R0</a>]</span> previously suggested this sort of facility under the name <code class="sourceCode cpp"><span class="kw">operator</span> <span class="cf">try</span></code>. As mentioned, Rust previously had an error propagation macro named <code class="sourceCode cpp"><span class="cf">try</span><span class="op">!</span></code> and multiple other languages have such an error propagation operator (<a href="https://ziglang.org/documentation/master/#try">Zig</a>, <a href="https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html">Swift</a>, <a href="http://joeduffyblog.com/2016/02/07/the-error-model/">Midori</a>, etc.).</p>
<p>The problem is, in C++, <code class="sourceCode cpp"><span class="cf">try</span></code> is strongly associated with <em>exceptions</em>. That’s what a <code class="sourceCode cpp"><span class="cf">try</span></code> block is for: to catch exceptions. In <span class="citation" data-cites="P0709R4">[<a href="#ref-P0709R4" role="doc-biblioref">P0709R4</a>]</span>, there was a proposal for a <code class="sourceCode cpp"><span class="cf">try</span></code> expression (in §4.5.1). That, too, was tied in with exceptions. Not only for us is it tied into exceptions, but it’s used to <em>not</em> propagate the exception - <code class="sourceCode cpp"><span class="cf">try</span></code> blocks are for handling errors.</p>
<p>Having a facility for error propagation in C++ which has nothing to do with exceptions still use the keyword <code class="sourceCode cpp"><span class="cf">try</span></code> and do the opposite of a what a <code class="sourceCode cpp"><span class="cf">try</span></code> block does today (i.e. propagate the error, instead of handling it) would be, I think, quite misleading. And the goal here isn’t to interact with exceptions at all - it’s simply to provide automated error propagation for those error handling cases that <em>don’t</em> use exceptions.</p>
<h3 data-number="4.1.2" id="why-not-prefix"><span class="header-section-number">4.1.2</span> Why not prefix?<a href="#why-not-prefix" class="self-link"></a></h3>
<p>Once we settle on some punctuator, there’s the question of whether this punctuator should be used as a prefix operator or a postfix operator. As prefix, there is no ambiguity with <code class="sourceCode cpp"><span class="op">?</span></code> at least, so we could use a more straightforward token. But I think postfix is quite a bit better. Consider the following example:</p>
<blockquote>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1"></a><span class="kw">struct</span> U <span class="op">{</span> <span class="op">...</span> <span class="op">}</span>;</span>
<span id="cb11-2"><a href="#cb11-2"></a></span>
<span id="cb11-3"><a href="#cb11-3"></a><span class="kw">struct</span> T <span class="op">{</span></span>
<span id="cb11-4"><a href="#cb11-4"></a> <span class="kw">auto</span> next<span class="op">()</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>U, E<span class="op">></span>;</span>
<span id="cb11-5"><a href="#cb11-5"></a><span class="op">}</span>;</span>
<span id="cb11-6"><a href="#cb11-6"></a></span>
<span id="cb11-7"><a href="#cb11-7"></a><span class="kw">auto</span> lookup<span class="op">()</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>T, E<span class="op">></span>;</span>
<span id="cb11-8"><a href="#cb11-8"></a></span>
<span id="cb11-9"><a href="#cb11-9"></a><span class="kw">auto</span> func<span class="op">()</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>U, E<span class="op">></span> <span class="op">{</span></span>
<span id="cb11-10"><a href="#cb11-10"></a> <span class="co">// as postfix</span></span>
<span id="cb11-11"><a href="#cb11-11"></a> U u <span class="op">=</span> lookup<span class="op">()??.</span>next<span class="op">()??</span>;</span>
<span id="cb11-12"><a href="#cb11-12"></a></span>
<span id="cb11-13"><a href="#cb11-13"></a> <span class="co">// using the monadic operations</span></span>
<span id="cb11-14"><a href="#cb11-14"></a> U u <span class="op">=</span> lookup<span class="op">().</span>and_then<span class="op">(&</span>T<span class="op">::</span>next<span class="op">)</span>;</span>
<span id="cb11-15"><a href="#cb11-15"></a></span>
<span id="cb11-16"><a href="#cb11-16"></a> <span class="co">// as prefix</span></span>
<span id="cb11-17"><a href="#cb11-17"></a> U u <span class="op">=</span> <span class="op">?(?</span>lookup<span class="op">()).</span>next<span class="op">()</span>;</span>
<span id="cb11-18"><a href="#cb11-18"></a></span>
<span id="cb11-19"><a href="#cb11-19"></a> do_something_with<span class="op">(</span>u<span class="op">)</span>;</span>
<span id="cb11-20"><a href="#cb11-20"></a></span>
<span id="cb11-21"><a href="#cb11-21"></a> <span class="cf">return</span> u;</span>
<span id="cb11-22"><a href="#cb11-22"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>The postfix version chains in a way that is quite easy to read.</p>
<p>Using the monadic operations (<span class="citation" data-cites="P2505R4">[<a href="#ref-P2505R4" role="doc-biblioref">P2505R4</a>]</span>) is fine, they’re nice in this case (which is basically optimal for them) but they tend to be quite tedious once you stray from this exact formulation (e.g. if <code class="sourceCode cpp">T<span class="op">::</span>next<span class="op">()</span></code> took another argument).</p>
<p>The prefix version is borderline illegible.</p>
<p>Even if we consider only one or the other side of the member access as needing propagation:</p>
<ul>
<li>Accessing a member after propagating: <code class="sourceCode cpp">x<span class="op">??.</span>y</code> vs <code class="sourceCode cpp"><span class="op">(?</span>x<span class="op">).</span>y</code></li>
<li>Propagating after accessing a member: <code class="sourceCode cpp">x<span class="op">.</span>y<span class="op">??</span></code> vs <code class="sourceCode cpp"><span class="op">?</span>x<span class="op">.</span>y</code> or <code class="sourceCode cpp"><span class="op">?(</span>x<span class="op">.</span>y<span class="op">)</span></code></li>
</ul>
<p>The postfix operator is quite a bit easier to understand, since it’s always right next to the expression that is potentially the error.</p>
<h3 data-number="4.1.3" id="in-other-languages"><span class="header-section-number">4.1.3</span> <code class="sourceCode cpp"><span class="op">??</span></code> in other languages<a href="#in-other-languages" class="self-link"></a></h3>
<p><code class="sourceCode cpp"><span class="op">??</span></code> is called a “null (or nil) coalescing operator” in some languages (like C# or JavaScript or Swift) where <code class="sourceCode cpp">x <span class="op">??</span> y</code> is roughly equivalent to what C++ would spell as <code class="sourceCode cpp">x <span class="op">?</span> <span class="op">*</span>x <span class="op">:</span> y</code> except that <code class="sourceCode cpp">x</code> is only evaluated once. Kotlin spells this operator <code class="sourceCode cpp"><span class="op">?:</span></code>, but it behaves differently from the gcc extension since <code class="sourceCode cpp">x <span class="op">?:</span> y</code> in gcc evaluates as <code class="sourceCode cpp">x <span class="op">?</span> x <span class="op">:</span> y</code> rather than <code class="sourceCode cpp">x <span class="op">?</span> <span class="op">*</span>x <span class="op">:</span> y</code>.</p>
<p>For <code class="sourceCode cpp">x</code> being some kind of <code class="sourceCode cpp">std<span class="op">::</span>optional<span class="op"><</span>T<span class="op">></span></code> or <code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op"><</span>T, E<span class="op">></span></code>, this can <em>mostly</em> already be spelled <code class="sourceCode cpp">x<span class="op">.</span>value_or<span class="op">(</span>y<span class="op">)</span></code>. The difference is that here <code class="sourceCode cpp">y</code> is unconditionally evaluated, which is why <span class="citation" data-cites="P2218R0">[<a href="#ref-P2218R0" role="doc-biblioref">P2218R0</a>]</span> proposes a separate <code class="sourceCode cpp">opt<span class="op">.</span>value_or_else<span class="op">(</span>f<span class="op">)</span></code> which invokes <code class="sourceCode cpp">f</code>. Which would make a proper equivalence be spelled <code class="sourceCode cpp">x<span class="op">.</span>value_or_else<span class="op">([&]{</span> <span class="cf">return</span> y; <span class="op">})</span></code>.</p>
<p>I’m not aware of any proposals to add this particular operator in C++, but because we already have two types that directly provide that functionality (as would many other non-<code class="sourceCode cpp">std</code> flavors thereof), and because it’s fairly straightforward to write such an algorithm generically, it wouldn’t seem especially valuable to have a dedicated operator for this functionality – so it’s probably safe to take for this use-case.</p>
<p>It certainly would be nice to have both, but given a choice between a null coalescing operator and an error propagation one, I’d choose the latter.`</p>
<p>Of course, now we have to talk about semantics.</p>
<h2 data-number="4.2" id="semantics"><span class="header-section-number">4.2</span> Semantics<a href="#semantics" class="self-link"></a></h2>
<p>This paper suggests that <code class="sourceCode cpp"><span class="op">??</span></code> evaluate roughly as follows:</p>
<table>
<tbody>
<tr class="odd">
<td><div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1"></a><span class="kw">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>std<span class="op">::</span>string, E<span class="op">></span></span>
<span id="cb12-2"><a href="#cb12-2"></a><span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3"></a></span>
<span id="cb12-4"><a href="#cb12-4"></a></span>
<span id="cb12-5"><a href="#cb12-5"></a> <span class="dt">int</span> f <span class="op">=</span> foo<span class="op">(</span>i<span class="op">)??</span>;</span>
<span id="cb12-6"><a href="#cb12-6"></a></span>
<span id="cb12-7"><a href="#cb12-7"></a></span>
<span id="cb12-8"><a href="#cb12-8"></a></span>
<span id="cb12-9"><a href="#cb12-9"></a></span>
<span id="cb12-10"><a href="#cb12-10"></a></span>
<span id="cb12-11"><a href="#cb12-11"></a></span>
<span id="cb12-12"><a href="#cb12-12"></a></span>
<span id="cb12-13"><a href="#cb12-13"></a></span>
<span id="cb12-14"><a href="#cb12-14"></a></span>
<span id="cb12-15"><a href="#cb12-15"></a> <span class="dt">int</span> b <span class="op">=</span> bar<span class="op">(</span>i<span class="op">)??</span>;</span>
<span id="cb12-16"><a href="#cb12-16"></a></span>
<span id="cb12-17"><a href="#cb12-17"></a></span>
<span id="cb12-18"><a href="#cb12-18"></a></span>
<span id="cb12-19"><a href="#cb12-19"></a></span>
<span id="cb12-20"><a href="#cb12-20"></a></span>
<span id="cb12-21"><a href="#cb12-21"></a></span>
<span id="cb12-22"><a href="#cb12-22"></a></span>
<span id="cb12-23"><a href="#cb12-23"></a></span>
<span id="cb12-24"><a href="#cb12-24"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, f, b<span class="op">)</span>;</span>
<span id="cb12-25"><a href="#cb12-25"></a><span class="op">}</span></span></code></pre></div></td>
<td><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">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>std<span class="op">::</span>string, E<span class="op">></span></span>
<span id="cb13-2"><a href="#cb13-2"></a><span class="op">{</span></span>
<span id="cb13-3"><a href="#cb13-3"></a> <span class="kw">using</span> <em>_Return</em> <span class="op">=</span> std<span class="op">::</span>error_propagation_traits<span class="op"><</span></span>
<span id="cb13-4"><a href="#cb13-4"></a> std<span class="op">::</span>expected<span class="op"><</span>std<span class="op">::</span>string, E<span class="op">>></span>;</span>
<span id="cb13-5"><a href="#cb13-5"></a></span>
<span id="cb13-6"><a href="#cb13-6"></a> <span class="kw">auto</span><span class="op">&&</span> <em>__f</em> <span class="op">=</span> foo<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb13-7"><a href="#cb13-7"></a> <span class="kw">using</span> <em>_TraitsF</em> <span class="op">=</span> std<span class="op">::</span>error_propagation_traits<span class="op"><</span></span>
<span id="cb13-8"><a href="#cb13-8"></a> std<span class="op">::</span>remove_cvref_t<span class="op"><</span><span class="kw">decltype</span><span class="op">(</span><em>__f</em><span class="op">)>></span>;</span>
<span id="cb13-9"><a href="#cb13-9"></a> <span class="cf">if</span> <span class="op">(</span><span class="kw">not</span> <em>_TraitsF</em><span class="op">::</span>has_value<span class="op">(</span><em>__f</em><span class="op">))</span> <span class="op">{</span></span>
<span id="cb13-10"><a href="#cb13-10"></a> <span class="cf">return</span> <em>_Return</em><span class="op">::</span>from_error<span class="op">(</span></span>
<span id="cb13-11"><a href="#cb13-11"></a> <em>_TraitsF</em><span class="op">::</span>extract_error<span class="op">(</span>FWD<span class="op">(</span><em>__f</em><span class="op">)))</span>;</span>
<span id="cb13-12"><a href="#cb13-12"></a> <span class="op">}</span></span>
<span id="cb13-13"><a href="#cb13-13"></a> <span class="dt">int</span> f <span class="op">=</span> <em>_TraitsF</em><span class="op">::</span>extract_value<span class="op">(</span>FWD<span class="op">(</span><em>__f</em><span class="op">))</span>;</span>
<span id="cb13-14"><a href="#cb13-14"></a></span>
<span id="cb13-15"><a href="#cb13-15"></a> <span class="kw">auto</span><span class="op">&&</span> <em>__b</em> <span class="op">=</span> bar<span class="op">(</span>i<span class="op">)</span>;</span>
<span id="cb13-16"><a href="#cb13-16"></a> <span class="kw">using</span> <em>_TraitsB</em> <span class="op">=</span> std<span class="op">::</span>error_propagation_traits<span class="op"><</span></span>
<span id="cb13-17"><a href="#cb13-17"></a> std<span class="op">::</span>remove_cvref_t<span class="op"><</span><span class="kw">decltype</span><span class="op">(</span><em>__b</em><span class="op">)>></span>;</span>
<span id="cb13-18"><a href="#cb13-18"></a> <span class="cf">if</span> <span class="op">(</span><span class="kw">not</span> <em>_TraitsB</em><span class="op">::</span>has_value<span class="op">(</span>__b<span class="op">))</span> <span class="op">{</span></span>
<span id="cb13-19"><a href="#cb13-19"></a> <span class="cf">return</span> <em>_Return</em><span class="op">::</span>from_error<span class="op">(</span></span>
<span id="cb13-20"><a href="#cb13-20"></a> <em>_TraitsB</em><span class="op">::</span>extract_error<span class="op">(</span>FWD<span class="op">(</span><em>__b</em><span class="op">)))</span>;</span>
<span id="cb13-21"><a href="#cb13-21"></a> <span class="op">}</span></span>
<span id="cb13-22"><a href="#cb13-22"></a> <span class="dt">int</span> b <span class="op">=</span> <em>_TraitsB</em><span class="op">::</span>extract_value<span class="op">(</span>FWD<span class="op">(</span><em>__b</em><span class="op">))</span>;</span>
<span id="cb13-23"><a href="#cb13-23"></a></span>
<span id="cb13-24"><a href="#cb13-24"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, f, b<span class="op">)</span>;</span>
<span id="cb13-25"><a href="#cb13-25"></a><span class="op">}</span></span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>The functionality here is driven by a new traits type called <code class="sourceCode cpp">std<span class="op">::</span>error_propagation_traits</code>, such that a given specialization supports:</p>
<ul>
<li>telling us when the object is truthy: <code class="sourceCode cpp">has_value</code></li>
<li>extracting a value (<code class="sourceCode cpp">extract_value</code>) or error (<code class="sourceCode cpp">extract_error</code>) from it</li>
<li>constructing a new object from either a value (<code class="sourceCode cpp">from_value</code>, not necessary in the above example, but will demonstrate a use later) or an error (<code class="sourceCode cpp">from_error</code>)</li>
</ul>
<p>Note that this does not support deducing return type, since we need the return type in order to know how construct it - the above desugaring uses the return type of <code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op"><</span>std<span class="op">::</span>string, E<span class="op">></span></code> to know how to re-wrap the potential error that <code class="sourceCode cpp">foo<span class="op">(</span>i<span class="op">)</span></code> or <code class="sourceCode cpp">bar<span class="op">(</span>i<span class="op">)</span></code> could return. This is important because it avoids the overhead that nicer syntax like <code class="sourceCode cpp">std<span class="op">::</span>unexpected</code> or <code class="sourceCode cpp">outcome<span class="op">::</span>failure</code> introduces (neither of which allow for deducing return type anyway, at least unless the function unconditionally fails), while still allowing nicer syntax.</p>
<p>This isn’t really a huge loss, since in these contexts, you can’t really deduce the return type anyway - since you’ll have some error type and some value type. So this restriction isn’t actually restrictive in practice.</p>
<p>These functions are all very easy to implement for the kinds of types that would want to support a facility like <code class="sourceCode cpp"><span class="op">??</span></code>. Here are examples for <code class="sourceCode cpp">optional</code> and <code class="sourceCode cpp">expected</code> (with <code class="sourceCode cpp"><span class="kw">constexpr</span></code> omitted to fit):</p>
<table>
<tbody>
<tr class="odd">
<td><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">template</span> <span class="op"><</span><span class="kw">class</span> T<span class="op">></span></span>
<span id="cb14-2"><a href="#cb14-2"></a><span class="kw">struct</span> error_propagation_traits<span class="op"><</span>optional<span class="op"><</span>T<span class="op">>></span> <span class="op">{</span></span>
<span id="cb14-3"><a href="#cb14-3"></a> <span class="kw">using</span> value_type <span class="op">=</span> T;</span>
<span id="cb14-4"><a href="#cb14-4"></a> <span class="kw">using</span> error_type <span class="op">=</span> nullopt_t;</span>
<span id="cb14-5"><a href="#cb14-5"></a></span>
<span id="cb14-6"><a href="#cb14-6"></a> <span class="kw">auto</span> has_value<span class="op">(</span>optional<span class="op"><</span>T<span class="op">></span> <span class="kw">const</span><span class="op">&</span> o<span class="op">)</span> <span class="op">-></span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb14-7"><a href="#cb14-7"></a> <span class="cf">return</span> o<span class="op">.</span>has_value<span class="op">()</span>;</span>
<span id="cb14-8"><a href="#cb14-8"></a> <span class="op">}</span></span>
<span id="cb14-9"><a href="#cb14-9"></a></span>
<span id="cb14-10"><a href="#cb14-10"></a> <span class="co">// extractors</span></span>
<span id="cb14-11"><a href="#cb14-11"></a> <span class="kw">auto</span> extract_value<span class="op">(</span><span class="kw">auto</span><span class="op">&&</span> o<span class="op">)</span> <span class="op">-></span> <span class="kw">auto</span><span class="op">&&</span> <span class="op">{</span></span>
<span id="cb14-12"><a href="#cb14-12"></a> <span class="cf">return</span> <span class="op">*</span>FWD<span class="op">(</span>o<span class="op">)</span>;</span>
<span id="cb14-13"><a href="#cb14-13"></a> <span class="op">}</span></span>
<span id="cb14-14"><a href="#cb14-14"></a> <span class="kw">auto</span> extract_error<span class="op">(</span><span class="kw">auto</span><span class="op">&&)</span> <span class="op">-></span> error_type <span class="op">{</span></span>
<span id="cb14-15"><a href="#cb14-15"></a> <span class="cf">return</span> nullopt;</span>
<span id="cb14-16"><a href="#cb14-16"></a> <span class="op">}</span></span>
<span id="cb14-17"><a href="#cb14-17"></a></span>
<span id="cb14-18"><a href="#cb14-18"></a> <span class="co">// factories</span></span>
<span id="cb14-19"><a href="#cb14-19"></a> <span class="kw">auto</span> from_value<span class="op">(</span><span class="kw">auto</span><span class="op">&&</span> v<span class="op">)</span> <span class="op">-></span> optional<span class="op"><</span>T<span class="op">></span> <span class="op">{</span></span>
<span id="cb14-20"><a href="#cb14-20"></a> <span class="cf">return</span> optional<span class="op"><</span>T<span class="op">>(</span>in_place, FWD<span class="op">(</span>v<span class="op">))</span>;</span>
<span id="cb14-21"><a href="#cb14-21"></a> <span class="op">}</span></span>
<span id="cb14-22"><a href="#cb14-22"></a> <span class="kw">auto</span> from_error<span class="op">(</span>nullopt_t<span class="op">)</span> <span class="op">-></span> optional<span class="op"><</span>T<span class="op">></span> <span class="op">{</span></span>
<span id="cb14-23"><a href="#cb14-23"></a> <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb14-24"><a href="#cb14-24"></a> <span class="op">}</span></span>
<span id="cb14-25"><a href="#cb14-25"></a><span class="op">}</span>;</span></code></pre></div></td>
<td><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">template</span> <span class="op"><</span><span class="kw">class</span> T, <span class="kw">class</span> E<span class="op">></span></span>
<span id="cb15-2"><a href="#cb15-2"></a><span class="kw">struct</span> error_propagation_traits<span class="op"><</span>expected<span class="op"><</span>T, E<span class="op">>></span> <span class="op">{</span></span>
<span id="cb15-3"><a href="#cb15-3"></a> <span class="kw">using</span> value_type <span class="op">=</span> T;</span>
<span id="cb15-4"><a href="#cb15-4"></a> <span class="kw">using</span> error_type <span class="op">=</span> E;</span>
<span id="cb15-5"><a href="#cb15-5"></a></span>
<span id="cb15-6"><a href="#cb15-6"></a> <span class="kw">auto</span> has_value<span class="op">(</span>expected<span class="op"><</span>T, E<span class="op">></span> <span class="kw">const</span><span class="op">&</span> e<span class="op">)</span> <span class="op">-></span> <span class="dt">bool</span> <span class="op">{</span></span>
<span id="cb15-7"><a href="#cb15-7"></a> <span class="cf">return</span> e<span class="op">.</span>has_value<span class="op">()</span>;</span>
<span id="cb15-8"><a href="#cb15-8"></a> <span class="op">}</span></span>
<span id="cb15-9"><a href="#cb15-9"></a></span>
<span id="cb15-10"><a href="#cb15-10"></a> <span class="co">// extractors</span></span>
<span id="cb15-11"><a href="#cb15-11"></a> <span class="kw">auto</span> extract_value<span class="op">(</span><span class="kw">auto</span><span class="op">&&</span> e<span class="op">)</span> <span class="op">-></span> <span class="kw">auto</span><span class="op">&&</span> <span class="op">{</span></span>
<span id="cb15-12"><a href="#cb15-12"></a> <span class="cf">return</span> <span class="op">*</span>FWD<span class="op">(</span>e<span class="op">)</span>;</span>
<span id="cb15-13"><a href="#cb15-13"></a> <span class="op">}</span></span>
<span id="cb15-14"><a href="#cb15-14"></a> <span class="kw">auto</span> extract_error<span class="op">(</span><span class="kw">auto</span><span class="op">&&</span> e<span class="op">)</span> <span class="op">-></span> <span class="kw">auto</span><span class="op">&&</span> <span class="op">{</span></span>
<span id="cb15-15"><a href="#cb15-15"></a> <span class="cf">return</span> FWD<span class="op">(</span>e<span class="op">).</span>error<span class="op">()</span>;</span>
<span id="cb15-16"><a href="#cb15-16"></a> <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="co">// factories</span></span>
<span id="cb15-19"><a href="#cb15-19"></a> <span class="kw">auto</span> from_value<span class="op">(</span><span class="kw">auto</span><span class="op">&&</span> v<span class="op">)</span> <span class="op">-></span> expected<span class="op"><</span>T, E<span class="op">></span> <span class="op">{</span></span>
<span id="cb15-20"><a href="#cb15-20"></a> <span class="cf">return</span> expected<span class="op"><</span>T, E<span class="op">>(</span>in_place, FWD<span class="op">(</span>v<span class="op">))</span>;</span>
<span id="cb15-21"><a href="#cb15-21"></a> <span class="op">}</span></span>
<span id="cb15-22"><a href="#cb15-22"></a> <span class="kw">auto</span> from_error<span class="op">(</span><span class="kw">auto</span><span class="op">&&</span> e<span class="op">)</span> <span class="op">-></span> expected<span class="op"><</span>T, E<span class="op">></span> <span class="op">{</span></span>
<span id="cb15-23"><a href="#cb15-23"></a> <span class="cf">return</span> expected<span class="op"><</span>T, E<span class="op">>(</span>unexpect, FWD<span class="op">(</span>e<span class="op">))</span>;</span>
<span id="cb15-24"><a href="#cb15-24"></a> <span class="op">}</span></span>
<span id="cb15-25"><a href="#cb15-25"></a><span class="op">}</span>;</span></code></pre></div></td>
</tr>
</tbody>
</table>
<p>This also helps demonstrate the requirements for what <code class="sourceCode cpp">error_propagation_traits<span class="op"><</span>O<span class="op">></span></code> have to return:</p>
<ul>
<li><code class="sourceCode cpp">has_value</code> is invoked on an lvalue of type <code class="sourceCode cpp">O</code> and returns <code class="sourceCode cpp"><span class="dt">bool</span></code></li>
<li><code class="sourceCode cpp">extract_value</code> takes some kind of <code class="sourceCode cpp">O</code> and returns a type that, after stripping qualifiers, is <code class="sourceCode cpp">value_type</code></li>
<li><code class="sourceCode cpp">extract_error</code> takes some kind of <code class="sourceCode cpp">O</code> and returns a type that, after stripping qualifiers, is <code class="sourceCode cpp">error_type</code></li>
<li><code class="sourceCode cpp">from_value</code> and <code class="sourceCode cpp">from_error</code> each returns an <code class="sourceCode cpp">O</code> (though their arguments need not be specifically a <code class="sourceCode cpp">value_type</code> or an <code class="sourceCode cpp">error_type</code>)</li>
</ul>
<p>In the above case, <code class="sourceCode cpp">error_propagation_traits<span class="op"><</span>expected<span class="op"><</span>T, E<span class="op">>>::</span>extract_error</code> will always give some kind of reference to <code class="sourceCode cpp">E</code> (either <code class="sourceCode cpp">E<span class="op">&</span></code>, <code class="sourceCode cpp">E <span class="kw">const</span><span class="op">&</span></code>, <code class="sourceCode cpp">E<span class="op">&&</span></code>, or <code class="sourceCode cpp">E <span class="kw">const</span><span class="op">&&</span></code>, depending on the value category of the argument), while <code class="sourceCode cpp">error_propagation_traits<span class="op"><</span>optional<span class="op"><</span>T<span class="op">>>::</span>extract_error</code> will always be <code class="sourceCode cpp">std<span class="op">::</span>nullopt_t</code>, by value. Both are fine, it simply depends on the type.</p>
<p>Since the extractors are only invoked on an <code class="sourceCode cpp">O</code> directly, you can safely assume that the object passed in is basically a forwarding reference to <code class="sourceCode cpp">O</code>, so <code class="sourceCode cpp"><span class="kw">auto</span><span class="op">&&</span></code> is fine (at least pending something like <span class="citation" data-cites="P2481R1">[<a href="#ref-P2481R1" role="doc-biblioref">P2481R1</a>]</span>). The extractors have the implicit precondition that the object is in the state specified (e.g. <code class="sourceCode cpp">extract_value<span class="op">(</span>o<span class="op">)</span></code> should only be called if <code class="sourceCode cpp">has_value<span class="op">(</span>o<span class="op">)</span></code>, with the converse for <code class="sourceCode cpp">extract_error<span class="op">(</span>o<span class="op">)</span></code>). The factories can accept anything though, and should probably be constrained.</p>
<p>The choice of desugaring based specifically on the return type (rather than relying on each object to produce some kind of construction disambiguator like <code class="sourceCode cpp">nullopt_t</code> or <code class="sourceCode cpp">unexpected<span class="op"><</span>E<span class="op">></span></code>) is not only that we can be more performant, but also we can allow conversions between different kinds of error types, which is useful when joining various libraries together:</p>
<blockquote>
<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> foo<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> tl<span class="op">::</span>expected<span class="op"><</span><span class="dt">int</span>, E<span class="op">></span>;</span>
<span id="cb16-2"><a href="#cb16-2"></a><span class="kw">auto</span> bar<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span><span class="dt">int</span>, E<span class="op">></span>;</span>
<span id="cb16-3"><a href="#cb16-3"></a></span>
<span id="cb16-4"><a href="#cb16-4"></a><span class="kw">auto</span> strcat<span class="op">(</span><span class="dt">int</span> i<span class="op">)</span> <span class="op">-></span> Result<span class="op"><</span>string, E<span class="op">></span></span>
<span id="cb16-5"><a href="#cb16-5"></a><span class="op">{</span></span>
<span id="cb16-6"><a href="#cb16-6"></a> <span class="co">// this works</span></span>
<span id="cb16-7"><a href="#cb16-7"></a> <span class="cf">return</span> std<span class="op">::</span>format<span class="op">(</span><span class="st">"{}{}"</span>, foo<span class="op">(</span>i<span class="op">)??</span>, bar<span class="op">(</span>i<span class="op">)??)</span>;</span>
<span id="cb16-8"><a href="#cb16-8"></a><span class="op">}</span></span></code></pre></div>
</blockquote>
<p>As long as each of these various error types opts into <code class="sourceCode cpp">error_propagation_traits</code> so that they can properly be constructed from an error, this will work just fine.</p>
<h3 data-number="4.2.1" id="lifetime"><span class="header-section-number">4.2.1</span> Lifetime<a href="#lifetime" class="self-link"></a></h3>
<p>Let’s consider some function declarations, where <code class="sourceCode cpp">T</code>, <code class="sourceCode cpp">U</code>, <code class="sourceCode cpp">V</code>, and <code class="sourceCode cpp">E</code> are some well-behaved object types.</p>
<blockquote>
<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> foo<span class="op">(</span>T <span class="kw">const</span><span class="op">&)</span> <span class="op">-></span> V;</span>
<span id="cb17-2"><a href="#cb17-2"></a><span class="kw">auto</span> bar<span class="op">()</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>T, E<span class="op">></span>;</span>
<span id="cb17-3"><a href="#cb17-3"></a><span class="kw">auto</span> quux<span class="op">()</span> <span class="op">-></span> std<span class="op">::</span>expected<span class="op"><</span>U, E<span class="op">></span>;</span></code></pre></div>
</blockquote>
<p>Now, consider the following fragment:</p>
<blockquote>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1"></a><span class="kw">auto</span> a <span class="op">=</span> foo<span class="op">(</span>bar<span class="op">()??)</span>;</span></code></pre></div>
</blockquote>
<p>The lifetime implications here should follow from the rest of the rules of the languages. Temporaries are destroyed at the end of the full-expression, temporaries bound to references do lifetime extension. In this case, <code class="sourceCode cpp">bar<span class="op">()</span></code> is a temporary of type <code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op"><</span>T, E<span class="op">></span></code>, which lasts until the end of the statement, <code class="sourceCode cpp">bar<span class="op">()??</span></code> gives you a <code class="sourceCode cpp">T<span class="op">&&</span></code> which refers into that temporary - which will be bound to the parameter of <code class="sourceCode cpp">foo<span class="op">()</span></code> - but that’s safe because the <code class="sourceCode cpp">T</code> itself isn’t going to be destroyed until the <code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op"><</span>T, E<span class="op">></span></code> is destroyed, which is after the call to <code class="sourceCode cpp">foo<span class="op">()</span></code> ends.</p>
<p>Note that this behavior is not really possible to express today using a statement rewrite. The inline macros for <code class="sourceCode cpp">bar<span class="op">()??</span></code> would do something like this:</p>
<blockquote>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1"></a><span class="kw">auto</span> a <span class="op">=</span> foo<span class="op">(</span></span>
<span id="cb19-2"><a href="#cb19-2"></a> <span class="op">({</span></span>
<span id="cb19-3"><a href="#cb19-3"></a> <span class="kw">auto</span> __tmp <span class="op">=</span> bar<span class="op">()</span>;</span>
<span id="cb19-4"><a href="#cb19-4"></a> <span class="cf">if</span> <span class="op">(</span><span class="kw">not</span> __tmp<span class="op">)</span> <span class="cf">return</span> std<span class="op">::</span>move<span class="op">(</span>__tmp<span class="op">).</span>error<span class="op">()</span>;</span>
<span id="cb19-5"><a href="#cb19-5"></a> <span class="op">*</span>__tmp;</span>
<span id="cb19-6"><a href="#cb19-6"></a> <span class="co">// __tmp destroyed here</span></span>
<span id="cb19-7"><a href="#cb19-7"></a> <span class="op">})</span></span>
<span id="cb19-8"><a href="#cb19-8"></a><span class="op">)</span>;</span></code></pre></div>
</blockquote>
<p>Using the statement-expression extension, the <code class="sourceCode cpp">std<span class="op">::</span>expected<span class="op"><</span>T, E<span class="op">></span></code> will actually be destroyed <em>before</em> the call to <code class="sourceCode cpp">foo</code>, which means we have a dangling reference.</p>
<p>The coroutine rewrite wouldn’t have this problem, for the same reason the suggested <code class="sourceCode cpp">bar<span class="op">()??</span></code> approach doesn’t:</p>
<blockquote>
<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">auto</span> a <span class="op">=</span> foo<span class="op">(</span><span class="kw">co_await</span> bar<span class="op">())</span>;</span></code></pre></div>
</blockquote>
<p>Now consider:</p>