-
Notifications
You must be signed in to change notification settings - Fork 22
/
p1870r1.html
1084 lines (1072 loc) · 101 KB
/
p1870r1.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="2019-11-08" />
<title>forwarding-range<T> is too subtle</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%;}
</style>
<style>
code.sourceCode > span { display: inline-block; line-height: 1.25; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
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 {
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; }
div#refs p { padding-left: 32px; text-indent: -32px; }
</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; }
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/vnd.microsoft.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"><em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em><code class="sourceCode cpp"><span class="op"><</span>T<span class="op">></span></code> is too subtle</h1>
<table style="border:none;float:right">
<tr>
<td>Document #: </td>
<td>P1870R1</td>
</tr>
<tr>
<td>Date: </td>
<td>2019-11-08</td>
</tr>
<tr>
<td style="vertical-align:top">Project: </td>
<td>Programming Language C++<br>
LEWG<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="#introduction"><span class="toc-section-number">2</span> Introduction<span></span></a></li>
<li><a href="#naming"><span class="toc-section-number">3</span> Naming<span></span></a></li>
<li><a href="#opting-into-forwarding-range"><span class="toc-section-number">4</span> Opting into <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em><span></span></a><ul>
<li><a href="#history"><span class="toc-section-number">4.1</span> History<span></span></a></li>
<li><a href="#issues-with-overloading"><span class="toc-section-number">4.2</span> Issues with overloading<span></span></a></li>
<li><a href="#how-many-mechanisms-do-we-need"><span class="toc-section-number">4.3</span> How many mechanisms do we need?<span></span></a></li>
<li><a href="#hard-to-get-correct"><span class="toc-section-number">4.4</span> Hard to get correct<span></span></a></li>
</ul></li>
<li><a href="#proposal"><span class="toc-section-number">5</span> Proposal<span></span></a><ul>
<li><a href="#wording"><span class="toc-section-number">5.1</span> Wording<span></span></a></li>
</ul></li>
<li><a href="#acknowledgements"><span class="toc-section-number">6</span> Acknowledgements<span></span></a></li>
<li><a href="#references"><span class="toc-section-number">7</span> References<span></span></a></li>
</ul>
</div>
<h1 id="revision-history" style="border-bottom:1px solid #cccccc"><span class="header-section-number">1</span> Revision History<a href="#revision-history" class="self-link"></a></h1>
<p>R0 <span class="citation" data-cites="P1870R0">[<a href="#ref-P1870R0" role="doc-biblioref">P1870R0</a>]</span> of this paper was presented to LEWG in Belfast. There was consensus to change the opt-in mechanism to use the trait rather than the non-member function as presented in the paper. However, there was unanimous dissent to remove the ability to invoke <code class="sourceCode cpp">ranges<span class="op">::</span>begin</code> (and other CPOs) on rvalues. This draft adds that ability back.</p>
<p>In short, the only change then is the opt-in mechanism. All other functionality is preserved.</p>
<p>This paper also addresses the NB comments <a href="https://github.com/cplusplus/nbballot/issues/275">US279</a> and <a href="https://github.com/cplusplus/nbballot/issues/276">GB280</a>, and is relevant to the resolution of <a href="https://github.com/cplusplus/nbballot/issues/272">US276</a> and <a href="https://github.com/cplusplus/nbballot/issues/282">US286</a>.</p>
<h1 id="introduction" style="border-bottom:1px solid #cccccc"><span class="header-section-number">2</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>One of the concepts introduces by Ranges is <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>. The salient aspect of what makes a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> is stated in <a href="http://eel.is/c++draft/range.range">[range.range]</a>:</p>
<blockquote>
<p>the validity of iterators obtained from the object denoted by <code class="sourceCode cpp">E</code> is not tied to the lifetime of that object.</p>
</blockquote>
<p>clarified more in the subsequent note:</p>
<blockquote>
<p><em>[ Note<em>: Since the validity of iterators is not tied to the lifetime of an object whose type models <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, a function can accept arguments of such a type by value and return iterators obtained from it without danger of dangling. </em>— end note ]</em></p>
</blockquote>
<p>For example, <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op"><</span>T<span class="op">></span></code> is not a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> because any iterator into a <code class="sourceCode cpp">vector</code> is of course dependent on the lifetime of the <code class="sourceCode cpp">vector</code> itself. On the other hand, <code class="sourceCode cpp">std<span class="op">::</span>string_view</code> <em>is</em> a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> because it does not actually own anything - any iterator you get out of it has its lifetime tied to some other object entirely.</p>
<p>But while <code class="sourceCode cpp">span</code> and <code class="sourceCode cpp">subrange</code> each model <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, not all views do. For instance, <code class="sourceCode cpp">transform_view</code> would not because its iterators’ validity would be tied to the unary function that is the actual transform. You could increment those iterators, but you couldn’t dereference them. Likewise, <code class="sourceCode cpp">filter_view</code>’s iterator validity is going to be based on its predicate.</p>
<p>Really, a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> is quite a rare creature.<a href="#fn1" class="footnote-ref" id="fnref1" role="doc-noteref"><sup>1</sup></a></p>
<p>Value category also plays into this. Notably, <em>lvalue</em> ranges all model <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> – the “object” in question in this case is an lvalue reference, and the validity of iterators into a range are never going to be tied to the lifetime of some reference to that range. For instance, <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op"><</span>T<span class="op">></span></code> is not a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, but <code class="sourceCode cpp">std<span class="op">::</span>vector<span class="op"><</span>T<span class="op">>&</span></code> is. The only question is about <em>rvalue</em> ranges. If I have a function that either takes a range by forwarding reference or by value, I have to know what I can do with it.</p>
<p>Ranges uses this in two kinds of places:</p>
<ul>
<li>Many algorithms return iterators into a range. Those algorithms conditionally return either <code class="sourceCode cpp">iterator_t<span class="op"><</span>R<span class="op">></span></code> or <code class="sourceCode cpp">dangling</code> based on whether or not <code class="sourceCode cpp">R</code> satisfies <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> (because if <code class="sourceCode cpp">R</code> did not, then such iterators would not be valid, so they are not returned). This type is called <code class="sourceCode cpp">safe_iterator_t<span class="op"><</span>R<span class="op">></span></code> and appears over 100 times in <a href="http://eel.is/c++draft/algorithms">[algorithms]</a>.</li>
<li>Range adapters can only be used on rvalue ranges if they satisfy either <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> or they decay to a <code class="sourceCode cpp">view</code>. The former because you may need to keep iterators into them past their lifetime, and the latter because if you can cheaply copy it than that works too. This higher-level concept is called <code class="sourceCode cpp">viewable_range</code>, and every range adapter depends on it.</li>
</ul>
<p>That is, <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> is a very important concept. It is used practically everywhere. It also conveys a pretty subtle and very rare feature of a type: that its iterators can outlive it. Syntactically, there is no difference between a <code class="sourceCode cpp">range</code>, a <code class="sourceCode cpp">view</code>, and a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, so the question is - how does a type declare itself to have this feature?</p>
<h1 id="naming" style="border-bottom:1px solid #cccccc"><span class="header-section-number">3</span> Naming<a href="#naming" class="self-link"></a></h1>
<p>The name <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> is problematic. There is a concept <code class="sourceCode cpp">std<span class="op">::</span>forward_range</code> which is completely unrelated. A fairly common first response is that it has something to do with forwarding iterators. But the name actually comes from the question of whether you can use a forwarding reference <code class="sourceCode cpp">range</code> safely.</p>
<p>However, coming up with a good name for it is very difficult. The concept has to refer to the range, but the salient aspect really has more to do with the iterators. Words that seem relevant are detachable, untethered, unfettered, nondangling. But then applying them to the range ends up being a mouthful: <code class="sourceCode cpp">range_with_detachable_iterators</code>. Granted, this concept isn’t <em>directly</em> used in too many places so maybe a long name is fine.</p>
<p>The naming direction this proposal takes is to use the name <code class="sourceCode cpp">safe_range</code>, based on the existence of <code class="sourceCode cpp">safe_iterator</code> and <code class="sourceCode cpp">safe_subrange</code>. It still doesn’t seem like a great name though, but at least all the relevant library things are similarly named.</p>
<p>Also the concept is still exposition-only, despite being a fairly important concept that people may want to use in their own code. This can be worked around:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1"></a><span class="kw">template</span><span class="op"><</span><span class="kw">class</span> R<span class="op">></span></span>
<span id="cb1-2"><a href="#cb1-2"></a><span class="kw">concept</span> my_forwarding_range <span class="op">=</span> std<span class="op">::</span>range<span class="op"><</span>R<span class="op">></span></span>
<span id="cb1-3"><a href="#cb1-3"></a> <span class="op">&&</span> std<span class="op">::</span>same_as<span class="op"><</span>std<span class="op">::</span>safe_iterator_t<span class="op"><</span>R<span class="op">></span>, std<span class="op">::</span>iterator_t<span class="op"><</span>R<span class="op">>></span>;</span></code></pre></div>
<p>But this seems like the kind of thing the standard library should provide directly.</p>
<h1 id="opting-into-forwarding-range" style="border-bottom:1px solid #cccccc"><span class="header-section-number">4</span> Opting into <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em><a href="#opting-into-forwarding-range" class="self-link"></a></h1>
<p>Types must opt into <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, and this is done by having non-member <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code> overloads that must take the type by either value or rvalue reference. At first glance, it might seem like this is impossible to do in the language but Ranges accomplishes this through the clever<a href="#fn2" class="footnote-ref" id="fnref2" role="doc-noteref"><sup>2</sup></a> use of poison-pill overload:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">namespace</span> __begin <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2"></a> <span class="co">// poison pill</span></span>
<span id="cb2-3"><a href="#cb2-3"></a> <span class="kw">template</span> <span class="op"><</span><span class="kw">typename</span> T<span class="op">></span> <span class="dt">void</span> begin<span class="op">(</span>T<span class="op">&&)</span> <span class="op">=</span> <span class="kw">delete</span>;</span>
<span id="cb2-4"><a href="#cb2-4"></a></span>
<span id="cb2-5"><a href="#cb2-5"></a> <span class="kw">template</span> <span class="op"><</span><span class="kw">typename</span> R<span class="op">></span></span>
<span id="cb2-6"><a href="#cb2-6"></a> <span class="kw">concept</span> has_non_member <span class="op">=</span> <span class="kw">requires</span> <span class="op">(</span>R<span class="op">&&</span> r<span class="op">)</span> <span class="op">{</span></span>
<span id="cb2-7"><a href="#cb2-7"></a> begin<span class="op">(</span>std<span class="op">::</span>forward<span class="op"><</span>R<span class="op">>(</span>r<span class="op">))</span>;</span>
<span id="cb2-8"><a href="#cb2-8"></a> <span class="op">}</span>;</span>
<span id="cb2-9"><a href="#cb2-9"></a><span class="op">}</span></span>
<span id="cb2-10"><a href="#cb2-10"></a></span>
<span id="cb2-11"><a href="#cb2-11"></a><span class="kw">namespace</span> N <span class="op">{</span></span>
<span id="cb2-12"><a href="#cb2-12"></a> <span class="kw">struct</span> my_vector <span class="op">{</span> <span class="co">/* ... */</span> <span class="op">}</span>;</span>
<span id="cb2-13"><a href="#cb2-13"></a> <span class="kw">auto</span> begin<span class="op">(</span>my_vector <span class="kw">const</span><span class="op">&)</span>;</span>
<span id="cb2-14"><a href="#cb2-14"></a><span class="op">}</span></span></code></pre></div>
<p>Does <code class="sourceCode cpp">N<span class="op">::</span>my_vector</code> satisfy the concept <code class="sourceCode cpp">__begin<span class="op">::</span>has_non_member</code>? It does not. The reason is that the poison pill candidate binds an rvalue reference to the argument while the ADL candidate binds an lvalue reference, and tiebreaker of rvalue reference to lvalue reference happens much earlier than non-template to template. The only way to have a better match than the poison pill for rvalues is to either have a function/function template that takes its argument by value or rvalue reference, or to have a function template that takes a constrained forwarding reference.</p>
<p>This is a pretty subtle design decision - why did we decide to use the existence of non-member overloads as the opt-in?</p>
<h2 id="history"><span class="header-section-number">4.1</span> History<a href="#history" class="self-link"></a></h2>
<p>This design comes from <span class="citation" data-cites="stl2.547">[<a href="#ref-stl2.547" role="doc-biblioref">stl2.547</a>]</span>, with the expressed intent:</p>
<blockquote>
<p>Redesign begin/end CPOs to eliminate deprecated behavior and to force range types to opt in to working with rvalues, thereby giving users a way to detect that, for a particular range type, iterator validity does not depend on the range’s lifetime.</p>
</blockquote>
<p>which led to <span class="citation" data-cites="P0970R1">[<a href="#ref-P0970R1" role="doc-biblioref">P0970R1</a>]</span>, which describes the earlier problems with <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">()</span></code> thusly:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> For the sake of compatibility with <code class="sourceCode cpp">std<span class="op">::</span>begin</code> and ease of migration, <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>begin</code> accepted rvalues and treated them the same as <code class="sourceCode cpp"><span class="kw">const</span></code> lvalues. This behavior was deprecated because it is fundamentally unsound: any iterator returned by such an overload is highly likely to dangle after the full-expression that contained the invocation of <code class="sourceCode cpp">begin</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> Another problem, and one that until recently seemed unrelated to the design of <code class="sourceCode cpp">begin</code>, was that algorithms that return iterators will wrap those iterators in <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>dangling<span class="op"><></span></code> if the range passed to them is an rvalue. This ignores the fact that for some range types — <code class="sourceCode cpp">std<span class="op">::</span>span</code>, <code class="sourceCode cpp">std<span class="op">::</span>string_view</code>, and P0789’s <code class="sourceCode cpp">subrange</code>, in particular — the iterator’s validity does not depend on the range’s lifetime at all. In the case where an rvalue of one of the above types is passed to an algorithm, returning a wrapped iterator is totally unnecessary.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span> The author believed that to fix the problem with <code class="sourceCode cpp">subrange</code> and <code class="sourceCode cpp">dangling</code> would require the addition of a new trait to give the authors of range types a way to say whether its iterators can safely outlive the range. That felt like a hack.</p>
</blockquote>
<p>This paper was presented in Rapperswil 2018, partially jointly with <span class="citation" data-cites="P0896R1">[<a href="#ref-P0896R1" role="doc-biblioref">P0896R1</a>]</span>, and as far as I can tell from the minutes, this subtlety was not discussed.</p>
<h2 id="issues-with-overloading"><span class="header-section-number">4.2</span> Issues with overloading<a href="#issues-with-overloading" class="self-link"></a></h2>
<p>In <span class="citation" data-cites="stl2.592">[<a href="#ref-stl2.592" role="doc-biblioref">stl2.592</a>]</span>, Eric Niebler points out that the current wording has the non-member <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code> for <code class="sourceCode cpp">subrange</code> taking it by rvalue reference instead of by value, meaning that <code class="sourceCode cpp"><span class="kw">const</span> subrange</code> doesn’t count as a <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>. But there is a potentially broader problem, which is that overload resolution will consider the <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code> functions for <code class="sourceCode cpp">subrange</code> even in contexts where they would be a worse match than the poison pill (i.e. they would involve conversions), and some of those contexts could lead to hard instantiation errors. So Eric suggests that the overload should be:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1"></a><span class="kw">friend</span> <span class="kw">constexpr</span> I begin<span class="op">(</span>same_as<span class="op"><</span>subrange<span class="op">></span> <span class="kw">auto</span> r<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> r<span class="op">.</span>begin<span class="op">()</span>; <span class="op">}</span></span></code></pre></div>
<p>Of the types in the standard library that should model <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, three of the four should take the same treatment (only <code class="sourceCode cpp">iota_view</code> doesn’t need to worry). That is, in order to really ensure correctness by avoiding any potential hard instantiation errors, we have to write non-member <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code> function templates that constrain their argument via <code class="sourceCode cpp">same_as<span class="op"><</span>R<span class="op">></span></code>?</p>
<p>The issue goes on to further suggest that perhaps the currect overload is really:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1"></a><span class="kw">friend</span> <span class="kw">constexpr</span> I begin<span class="op">(</span><em>same-ish</em><span class="op"><</span>subrange<span class="op">></span> <span class="kw">auto</span><span class="op">&&</span> r<span class="op">)</span> <span class="op">{</span> <span class="cf">return</span> r<span class="op">.</span>begin<span class="op">()</span>; <span class="op">}</span></span></code></pre></div>
<p>And there is an NB comment that suggests the <em><code class="sourceCode cpp">same<span class="op">-</span>ish</code></em><code class="sourceCode cpp"><span class="op"><</span>T<span class="op">></span> <span class="kw">auto</span><span class="op">&&</span></code> spelling for some times and <code class="sourceCode cpp">same_as<span class="op"><</span>T<span class="op">></span> <span class="kw">auto</span></code> spelling for others. What’s the distinction? To be honest, I do not understand.</p>
<p>Now we’ve started from needing a non-member <code class="sourceCode cpp">begin<span class="op">()</span></code>/<code class="sourceCode cpp">end<span class="op">()</span></code> that take an argument by value or rvalue reference – not necessarily to actually be invoked on an rvalue – but that runs into potential problems, that need to be solved by making that non-member a constrained template that either takes by value or forwarding reference, but constrained to a single type?</p>
<h2 id="how-many-mechanisms-do-we-need"><span class="header-section-number">4.3</span> How many mechanisms do we need?<a href="#how-many-mechanisms-do-we-need" class="self-link"></a></h2>
<p>At this point, we have three concepts in Ranges that have some sort of mechanism to opt-in/opt-out:</p>
<ul>
<li><em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>: provide a non-member <code class="sourceCode cpp">begin<span class="op">()</span></code>/<code class="sourceCode cpp">end<span class="op">()</span></code> that take their argument by value or rvalue reference (but really probably a constrained function template)</li>
<li><code class="sourceCode cpp">view</code>: opt-in via the <code class="sourceCode cpp">enable_view</code> type trait</li>
<li><code class="sourceCode cpp">sized_range</code>: opt-out via the <code class="sourceCode cpp">disable_sized_range</code> trait</li>
</ul>
<p>I don’t think we need different mechanisms for each trait. I know Eric and Casey viewed having to have a type trait as a hack, but it’s a hack around not having a language mechanism to express opt-in (see also <span class="citation" data-cites="P1900R0">[<a href="#ref-P1900R0" role="doc-biblioref">P1900R0</a>]</span>). It’s still the best hack we have, that’s the easiest to understand, that’s probably more compiler-efficient as well (overload resolution is expensive!)</p>
<h2 id="hard-to-get-correct"><span class="header-section-number">4.4</span> Hard to get correct<a href="#hard-to-get-correct" class="self-link"></a></h2>
<p>Now that MSVC’s standard library implementation is open source, we can take a look at how they went about implementing the opt-in for <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> in their implementation of <code class="sourceCode cpp">basic_string_view</code> <span class="citation" data-cites="msvc.basic_string_view">[<a href="#ref-msvc.basic_string_view" role="doc-biblioref">msvc.basic_string_view</a>]</span>:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1"></a><span class="pp">#ifdef __cpp_lib_concepts</span></span>
<span id="cb5-2"><a href="#cb5-2"></a> _NODISCARD <span class="kw">friend</span> <span class="kw">constexpr</span> const_iterator begin<span class="op">(</span><span class="kw">const</span> basic_string_view<span class="op">&</span> _Right<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3"></a> <span class="co">// non-member overload that accepts rvalues to model the exposition-only forwarding-range concept</span></span>
<span id="cb5-4"><a href="#cb5-4"></a> <span class="cf">return</span> _Right<span class="op">.</span>begin<span class="op">()</span>;</span>
<span id="cb5-5"><a href="#cb5-5"></a> <span class="op">}</span></span>
<span id="cb5-6"><a href="#cb5-6"></a> _NODISCARD <span class="kw">friend</span> <span class="kw">constexpr</span> const_iterator end<span class="op">(</span><span class="kw">const</span> basic_string_view<span class="op">&</span> _Right<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb5-7"><a href="#cb5-7"></a> <span class="co">// Ditto modeling forwarding-range</span></span>
<span id="cb5-8"><a href="#cb5-8"></a> <span class="cf">return</span> _Right<span class="op">.</span>end<span class="op">()</span>;</span>
<span id="cb5-9"><a href="#cb5-9"></a> <span class="op">}</span></span>
<span id="cb5-10"><a href="#cb5-10"></a><span class="pp">#endif </span><span class="co">// __cpp_lib_concepts</span></span></code></pre></div>
<p>Note that these overloads take their arguments by reference-to-<code class="sourceCode cpp"><span class="kw">const</span></code>. But the non-member overloads need to take their arguments by either value or rvalue reference, otherwise the poison pill is a better match, as described earlier. So at this moment, <code class="sourceCode cpp">std<span class="op">::</span>string_view</code> fails to satisfy <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>. If even Casey can make this mistake, how is anybody going to get it right?</p>
<h1 id="proposal" style="border-bottom:1px solid #cccccc"><span class="header-section-number">5</span> Proposal<a href="#proposal" class="self-link"></a></h1>
<p>The naming direction this proposal takes is to use the name <code class="sourceCode cpp">safe_range</code>, based on the existence of <code class="sourceCode cpp">safe_iterator</code> and <code class="sourceCode cpp">safe_subrange</code>. If a alternate name is preferred, the wording can simply be block replaced following the naming convention proposed in <span class="citation" data-cites="P1871R0">[<a href="#ref-P1871R0" role="doc-biblioref">P1871R0</a>]</span>. The proposal has four parts:</p>
<ul>
<li>Trait: introduce a new variable template <code class="sourceCode cpp">enable_safe_range</code>, with default value <code class="sourceCode cpp"><span class="kw">false</span><span class="op">.</span></code></li>
<li>Concept: rename the concept <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> to <code class="sourceCode cpp">safe_range</code>, make it non-exposition only, and have its definition be based on the type trait. Replace all uses of <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> with <code class="sourceCode cpp">safe_range</code> as appropriate.</li>
<li>CPO: Have <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">()</span></code> and <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">()</span></code>, and their const and reverse cousins, check the trait <code class="sourceCode cpp">enable_safe_range</code> and <em>only</em> allow lvalues unless this trait is true.</li>
<li>Library opt-in: Have the library types which currently opt-in to <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em> by providing non-member <code class="sourceCode cpp">begin</code> and <code class="sourceCode cpp">end</code> instead specialize <code class="sourceCode cpp">enable_safe_range</code>, and remove those overloads non-member overloads.</li>
</ul>
<h2 id="wording"><span class="header-section-number">5.1</span> Wording<a href="#wording" class="self-link"></a></h2>
<p><span class="ednote" style="color: #0000ff">[ Editor's note: The paper P1664R1 opts <code class="sourceCode cpp">iota_view</code> into modeling what is now the <code class="sourceCode cpp">safe_range</code> concept by adding non-member <code class="sourceCode cpp">begin<span class="op">()</span></code> and <code class="sourceCode cpp">end<span class="op">()</span></code>. When we merge both papers together, <code class="sourceCode cpp">iota_view</code> should <em>not</em> have those non-member functions added. This paper adds the new opt-in by specializing <code class="sourceCode cpp">enable_safe_range</code>. ]</span></p>
<p>Change 21.4.1 [string.view.synop] to opt into <code class="sourceCode cpp">enable_safe_range</code>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb6"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb6-1"><a href="#cb6-1"></a>namespace std {</span>
<span id="cb6-2"><a href="#cb6-2"></a> // [string.view.template], class template basic_string_view</span>
<span id="cb6-3"><a href="#cb6-3"></a> template<class charT, class traits = char_traits<charT>></span>
<span id="cb6-4"><a href="#cb6-4"></a> class basic_string_view;</span>
<span id="cb6-5"><a href="#cb6-5"></a> </span>
<span id="cb6-6"><a href="#cb6-6"></a><span class="va">+ template<class charT, class traits></span></span>
<span id="cb6-7"><a href="#cb6-7"></a><span class="va">+ inline constexpr bool enable_safe_range<basic_string_view<charT, traits>> = true; </span></span>
<span id="cb6-8"><a href="#cb6-8"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Change 21.4.2 [string.view.template] to remove the non-member <code class="sourceCode cpp">begin</code>/<code class="sourceCode cpp">end</code> overloads that were the old opt-in:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb7"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb7-1"><a href="#cb7-1"></a>template<class charT, class traits = char_traits<charT>></span>
<span id="cb7-2"><a href="#cb7-2"></a>class basic_string_view {</span>
<span id="cb7-3"><a href="#cb7-3"></a></span>
<span id="cb7-4"><a href="#cb7-4"></a><span class="st">- friend constexpr const_iterator begin(basic_string_view sv) noexcept { return sv.begin(); }</span></span>
<span id="cb7-5"><a href="#cb7-5"></a><span class="st">- friend constexpr const_iterator end(basic_string_view sv) noexcept { return sv.end(); }</span></span>
<span id="cb7-6"><a href="#cb7-6"></a></span>
<span id="cb7-7"><a href="#cb7-7"></a>};</span></code></pre></div>
</div>
</blockquote>
<p>Change 22.7.2 [span.syn] to opt into <code class="sourceCode cpp">enable_safe_range</code>:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb8"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb8-1"><a href="#cb8-1"></a>namespace std {</span>
<span id="cb8-2"><a href="#cb8-2"></a> // constants</span>
<span id="cb8-3"><a href="#cb8-3"></a> inline constexpr size_t dynamic_extent = numeric_limits<size_t>::max();</span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a> // [views.span], class template span</span>
<span id="cb8-6"><a href="#cb8-6"></a> template<class ElementType, size_t Extent = dynamic_extent></span>
<span id="cb8-7"><a href="#cb8-7"></a> class span;</span>
<span id="cb8-8"><a href="#cb8-8"></a> </span>
<span id="cb8-9"><a href="#cb8-9"></a><span class="va">+ template<class ElementType, size_t Extent></span></span>
<span id="cb8-10"><a href="#cb8-10"></a><span class="va">+ inline constexpr bool enable_safe_range<span<ElementType, Extent>> = true; </span></span>
<span id="cb8-11"><a href="#cb8-11"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Change 22.7.3.1 [span.overview] to remove the non-member <code class="sourceCode cpp">begin</code>/<code class="sourceCode cpp">end</code> overloads that were the old opt-in:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb9"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb9-1"><a href="#cb9-1"></a>namespace std {</span>
<span id="cb9-2"><a href="#cb9-2"></a> template<class ElementType, size_t Extent = dynamic_extent></span>
<span id="cb9-3"><a href="#cb9-3"></a> class span {</span>
<span id="cb9-4"><a href="#cb9-4"></a> [...]</span>
<span id="cb9-5"><a href="#cb9-5"></a> </span>
<span id="cb9-6"><a href="#cb9-6"></a><span class="st">- friend constexpr iterator begin(span s) noexcept { return s.begin(); }</span></span>
<span id="cb9-7"><a href="#cb9-7"></a><span class="st">- friend constexpr iterator end(span s) noexcept { return s.end(); }</span></span>
<span id="cb9-8"><a href="#cb9-8"></a></span>
<span id="cb9-9"><a href="#cb9-9"></a> private:</span>
<span id="cb9-10"><a href="#cb9-10"></a> pointer data_; // exposition only</span>
<span id="cb9-11"><a href="#cb9-11"></a> index_type size_; // exposition only</span>
<span id="cb9-12"><a href="#cb9-12"></a> };</span>
<span id="cb9-13"><a href="#cb9-13"></a> </span>
<span id="cb9-14"><a href="#cb9-14"></a> template<class Container></span>
<span id="cb9-15"><a href="#cb9-15"></a> span(const Container&) -> span<const typename Container::value_type>;</span>
<span id="cb9-16"><a href="#cb9-16"></a>} </span></code></pre></div>
</div>
</blockquote>
<p>Change 24.2 [ranges.syn] to introduce the new trait and the new non-exposition-only concept:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb10"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb10-1"><a href="#cb10-1"></a>#include <initializer_list></span>
<span id="cb10-2"><a href="#cb10-2"></a>#include <iterator></span>
<span id="cb10-3"><a href="#cb10-3"></a></span>
<span id="cb10-4"><a href="#cb10-4"></a>namespace std::ranges {</span>
<span id="cb10-5"><a href="#cb10-5"></a> [ ... ]</span>
<span id="cb10-6"><a href="#cb10-6"></a></span>
<span id="cb10-7"><a href="#cb10-7"></a> // [range.range], ranges </span>
<span id="cb10-8"><a href="#cb10-8"></a> template<class T></span>
<span id="cb10-9"><a href="#cb10-9"></a> concept range = <em>see below</em>;</span>
<span id="cb10-10"><a href="#cb10-10"></a></span>
<span id="cb10-11"><a href="#cb10-11"></a><span class="va">+ template <range T></span></span>
<span id="cb10-12"><a href="#cb10-12"></a><span class="va">+ inline constexpr bool enable_safe_range = false;</span></span>
<span id="cb10-13"><a href="#cb10-13"></a><span class="va">+</span></span>
<span id="cb10-14"><a href="#cb10-14"></a><span class="va">+ template<class T></span></span>
<span id="cb10-15"><a href="#cb10-15"></a><span class="va">+ concept safe_range = <em>see below</em>;</span></span>
<span id="cb10-16"><a href="#cb10-16"></a></span>
<span id="cb10-17"><a href="#cb10-17"></a> [ ... ] </span>
<span id="cb10-18"><a href="#cb10-18"></a> </span>
<span id="cb10-19"><a href="#cb10-19"></a> // [range.subrange], sub-ranges</span>
<span id="cb10-20"><a href="#cb10-20"></a> enum class subrange_kind : bool { unsized, sized };</span>
<span id="cb10-21"><a href="#cb10-21"></a></span>
<span id="cb10-22"><a href="#cb10-22"></a> template<input_or_output_iterator I, sentinel_for<I> S = I, subrange_kind K = see below></span>
<span id="cb10-23"><a href="#cb10-23"></a> requires (K == subrange_kind::sized || !sized_sentinel_for<S, I>)</span>
<span id="cb10-24"><a href="#cb10-24"></a> class subrange; </span>
<span id="cb10-25"><a href="#cb10-25"></a> </span>
<span id="cb10-26"><a href="#cb10-26"></a><span class="va">+ template<input_or_output_iterator I, sentinel_for<I> S, subrange_kind K></span></span>
<span id="cb10-27"><a href="#cb10-27"></a><span class="va">+ inline constexpr bool enable_safe_range<subrange<I, S, K>> = true; </span></span>
<span id="cb10-28"><a href="#cb10-28"></a> </span>
<span id="cb10-29"><a href="#cb10-29"></a> // [range.dangling], dangling iterator handling</span>
<span id="cb10-30"><a href="#cb10-30"></a> struct dangling;</span>
<span id="cb10-31"><a href="#cb10-31"></a></span>
<span id="cb10-32"><a href="#cb10-32"></a> template<range R></span>
<span id="cb10-33"><a href="#cb10-33"></a><span class="st">- using safe_iterator_t = conditional_t<<span class="diffdel"><em>forwarding-range</em></span><R>, iterator_t<R>, dangling>;</span></span>
<span id="cb10-34"><a href="#cb10-34"></a><span class="va">+ using safe_iterator_t = conditional_t<<span class="diffins">safe_range</span><R>, iterator_t<R>, dangling>;</span></span>
<span id="cb10-35"><a href="#cb10-35"></a></span>
<span id="cb10-36"><a href="#cb10-36"></a> template<range R></span>
<span id="cb10-37"><a href="#cb10-37"></a> using safe_subrange_t =</span>
<span id="cb10-38"><a href="#cb10-38"></a><span class="st">- conditional_t<<span class="diffdel"><em>forwarding-range</em></span><R>, subrange<iterator_t<R>>, dangling>;</span></span>
<span id="cb10-39"><a href="#cb10-39"></a><span class="va">+ conditional_t<<span class="diffins">safe_range</span><R>, subrange<iterator_t<R>>, dangling>;</span></span>
<span id="cb10-40"><a href="#cb10-40"></a> </span>
<span id="cb10-41"><a href="#cb10-41"></a> // [range.empty], empty view</span>
<span id="cb10-42"><a href="#cb10-42"></a> template<class T></span>
<span id="cb10-43"><a href="#cb10-43"></a> requires is_object_v<T></span>
<span id="cb10-44"><a href="#cb10-44"></a> class empty_view;</span>
<span id="cb10-45"><a href="#cb10-45"></a></span>
<span id="cb10-46"><a href="#cb10-46"></a><span class="va">+ template<class T></span></span>
<span id="cb10-47"><a href="#cb10-47"></a><span class="va">+ inline constexpr bool enable_safe_range<empty_view<T>> = true; </span></span>
<span id="cb10-48"><a href="#cb10-48"></a> </span>
<span id="cb10-49"><a href="#cb10-49"></a> </span>
<span id="cb10-50"><a href="#cb10-50"></a> [...]</span>
<span id="cb10-51"><a href="#cb10-51"></a> </span>
<span id="cb10-52"><a href="#cb10-52"></a> // [range.iota], iota view</span>
<span id="cb10-53"><a href="#cb10-53"></a> template<weakly_incrementable W, semiregular Bound = unreachable_sentinel_t></span>
<span id="cb10-54"><a href="#cb10-54"></a> requires weakly-equality-comparable-with<W, Bound></span>
<span id="cb10-55"><a href="#cb10-55"></a> class iota_view;</span>
<span id="cb10-56"><a href="#cb10-56"></a> </span>
<span id="cb10-57"><a href="#cb10-57"></a><span class="va">+ template<weakly_incrementable W, semiregular Bound></span></span>
<span id="cb10-58"><a href="#cb10-58"></a><span class="va">+ inline constexpr bool enable_safe_range<iota_view<W, Bound>> = true; </span></span>
<span id="cb10-59"><a href="#cb10-59"></a> </span>
<span id="cb10-60"><a href="#cb10-60"></a> [...]</span>
<span id="cb10-61"><a href="#cb10-61"></a> </span>
<span id="cb10-62"><a href="#cb10-62"></a> template<range R></span>
<span id="cb10-63"><a href="#cb10-63"></a> requires is_object_v<R></span>
<span id="cb10-64"><a href="#cb10-64"></a> class ref_view;</span>
<span id="cb10-65"><a href="#cb10-65"></a> </span>
<span id="cb10-66"><a href="#cb10-66"></a><span class="va">+ template<class T></span></span>
<span id="cb10-67"><a href="#cb10-67"></a><span class="va">+ inline constexpr bool enable_safe_range<ref_view<T>> = true; </span></span>
<span id="cb10-68"><a href="#cb10-68"></a></span>
<span id="cb10-69"><a href="#cb10-69"></a> [...]</span>
<span id="cb10-70"><a href="#cb10-70"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Change the definitions of <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">()</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">()</span></code>, and their <code class="sourceCode cpp">c</code> and <code class="sourceCode cpp">r</code> cousins, to only allow lvalues unless <code class="sourceCode cpp">enable_safe_range</code> is <code class="sourceCode cpp"><span class="kw">true</span></code>, and then be indifferent to member vs non-member (see also <span class="citation" data-cites="stl2.429">[<a href="#ref-stl2.429" role="doc-biblioref">stl2.429</a>]</span>). The poison pill no longer needs to force an overload taking a value or rvalue reference, it now only needs to force ADL - see also <span class="citation" data-cites="LWG3247">[<a href="#ref-LWG3247" role="doc-biblioref">LWG3247</a>]</span>), but this change is not made in this paper.</p>
<p>Change. 24.3.1 [range.access.begin]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The name <code class="sourceCode cpp">ranges<span class="op">::</span>begin</code> denotes a customization point object. <span class="addu">Given a subexpression <code class="sourceCode cpp">E</code> and an lvalue <code class="sourceCode cpp">t</code> that denotes the same object as <code class="sourceCode cpp">E</code>, if <code class="sourceCode cpp">E</code> is an rvalue and <code class="sourceCode cpp">enable_safe_range<span class="op"><</span>remove_cvref_t<span class="op"><</span><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))>></span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. Otherwise,</span> <span class="rm" style="color: #bf0303"><del>The expression</del></span> <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> <span class="rm" style="color: #bf0303"><del>for some subexpression <span><code class="sourceCode cpp">E</code></span></del></span> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> <span class="rm" style="color: #bf0303"><del><span><code class="sourceCode cpp">E <span class="op">+</span> <span class="dv">0</span></code></span> if <span><code class="sourceCode cpp">E</code></span></del></span> <span class="addu"><code class="sourceCode cpp">t <span class="op">+</span> <span class="dv">0</span></code> if <code class="sourceCode cpp">t</code></span> is <span class="rm" style="color: #bf0303"><del>an lvalue</del></span> of array type ([basic.compound]).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> Otherwise, <span class="rm" style="color: #bf0303"><del>if <span><code class="sourceCode cpp">E</code></span> is an lvalue,</del></span> <code><i>decay-copy</i>(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>.begin())</code> if it is a valid expression and its type <code class="sourceCode cpp">I</code> models <code class="sourceCode cpp">input_or_output_iterator</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> Otherwise, <code><i>decay-copy</i>(begin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if it is a valid expression and its type <code class="sourceCode cpp">I</code> models <code class="sourceCode cpp">input_or_output_iterator</code> with overload resolution performed in a context that includes the declarations:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb11-1"><a href="#cb11-1"></a>template<class T> void begin(T&&) = delete;</span>
<span id="cb11-2"><a href="#cb11-2"></a>template<class T> void begin(initializer_list<T>&&) = delete;</span></code></pre></div>
<p>and does not include a declaration of <code class="sourceCode cpp">ranges<span class="op">::</span>begin</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> Otherwise, <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. [ Note: This case can result in substitution failure when <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> appears in the immediate context of a template instantiation. <em>— end note</em> ]</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Note</em>: Whenever <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> is a valid expression, its type models <code class="sourceCode cpp">input_or_output_iterator</code>. — <em>end note</em> ]</p>
</blockquote>
<p>Change 24.3.2 [range.access.end] similarly:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The name <code class="sourceCode cpp">ranges<span class="op">::</span>end</code> denotes a customization point object. <span class="addu">Given a subexpression <code class="sourceCode cpp">E</code> and an lvalue <code class="sourceCode cpp">t</code> that denotes the same object as <code class="sourceCode cpp">E</code>, if <code class="sourceCode cpp">E</code> is an rvalue and <code class="sourceCode cpp">enable_safe_range<span class="op"><</span>remove_cvref_t<span class="op"><</span><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))>></span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. Otherwise,</span> <span class="rm" style="color: #bf0303"><del>The expression</del></span> <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">(</span>E<span class="op">)</span></code> <span class="rm" style="color: #bf0303"><del>for some subexpression <span><code class="sourceCode cpp">E</code></span></del></span> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> <code><span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span> + extent_v<T></code> if <code class="sourceCode cpp">E</code> is <span class="rm" style="color: #bf0303"><del>an lvalue</del></span> of array type ([basic.compound]) <code class="sourceCode cpp">T</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> Otherwise, <span class="rm" style="color: #bf0303"><del>if E is an lvalue,</del></span> <code><i>decay-copy</i>(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>.end())</code> if it is a valid expression and its type <code class="sourceCode cpp">S</code> models <code class="sourceCode cpp">sentinel_for<span class="op"><</span><span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">))></span></code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> Otherwise, <code><i>decay-copy</i>(end(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if it is a valid expression and its type <code class="sourceCode cpp">S</code> models <code class="sourceCode cpp">sentinel_for<span class="op"><</span><span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">))></span></code> with overload resolution performed in a context that includes the declarations:</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb12-1"><a href="#cb12-1"></a>template<class T> void end(T&&) = delete;</span>
<span id="cb12-2"><a href="#cb12-2"></a>template<class T> void end(initializer_list<T>&&) = delete;</span></code></pre></div>
<p>and does not include a declaration of <code class="sourceCode cpp">ranges<span class="op">::</span>end</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> Otherwise, <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. [ <em>Note</em>: This case can result in substitution failure when <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">(</span>E<span class="op">)</span></code> appears in the immediate context of a template instantiation. — <em>end note</em> ]</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Note</em>: Whenever <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">(</span>E<span class="op">)</span></code> is a valid expression, the types <code class="sourceCode cpp">S</code> and <code class="sourceCode cpp">I</code> of <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">(</span>E<span class="op">)</span></code> and <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> model <code class="sourceCode cpp">sentinel_for<span class="op"><</span>S, I<span class="op">></span></code>. — <em>end note</em> ]</p>
</blockquote>
<p>Change 24.3.5 [range.access.rbegin]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The name <code class="sourceCode cpp">ranges<span class="op">::</span>rbegin</code> denotes a customization point object. <span class="addu">Given a subexpression <code class="sourceCode cpp">E</code> and an lvalue <code class="sourceCode cpp">t</code> that denotes the same object as <code class="sourceCode cpp">E</code>, if <code class="sourceCode cpp">E</code> is an rvalue and <code class="sourceCode cpp">enable_safe_range<span class="op"><</span>remove_cvref_t<span class="op"><</span><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))>></span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. Otherwise,</span> <span class="rm" style="color: #bf0303"><del>The expression</del></span> <code class="sourceCode cpp">ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">)</span></code> <span class="rm" style="color: #bf0303"><del>for some subexpression <span><code class="sourceCode cpp">E</code></span></del></span> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> <span class="rm" style="color: #bf0303"><del>If <span><code class="sourceCode cpp">E</code></span> is an lvalue,</del></span> <code><i>decay-copy</i>(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>.rbegin())</code> if it is a valid expression and its type <code class="sourceCode cpp">I</code> models <code class="sourceCode cpp">input_or_output_iterator</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> Otherwise, <code><i>decay-copy</i>(rbegin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if it is a valid expression and its type <code class="sourceCode cpp">I</code> models <code class="sourceCode cpp">input_or_output_iterator</code> with overload resolution performed in a context that includes the declaration:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode default"><code class="sourceCode default"><span id="cb13-1"><a href="#cb13-1"></a>template<class T> void rbegin(T&&) = delete;</span></code></pre></div>
<p>and does not include a declaration of <code class="sourceCode cpp">ranges<span class="op">::</span>rbegin</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> Otherwise, <code>make_reverse_iterator(ranges::end(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if both <code>ranges::begin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>)</code> and <code>ranges::end(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>)</code> are valid expressions of the same type <code class="sourceCode cpp">I</code> which models <code class="sourceCode cpp">bidirectional_iterator</code> ([iterator.concept.bidir]).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> Otherwise, <code class="sourceCode cpp">ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. [ Note: This case can result in substitution failure when <code class="sourceCode cpp">ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">)</span></code> appears in the immediate context of a template instantiation. — <em>end note</em> ]</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Note</em>: Whenever <code class="sourceCode cpp">ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">)</span></code> is a valid expression, its type models <code class="sourceCode cpp">input_or_output_iterator</code>. — <em>end note</em> ]</p>
</blockquote>
<p>Change 24.3.6 [range.access.rend]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The name <code class="sourceCode cpp">ranges<span class="op">::</span>rend</code> denotes a customization point object. <span class="addu">Given a subexpression <code class="sourceCode cpp">E</code> and an lvalue <code class="sourceCode cpp">t</code> that denotes the same object as <code class="sourceCode cpp">E</code>, if <code class="sourceCode cpp">E</code> is an rvalue and <code class="sourceCode cpp">enable_safe_range<span class="op"><</span>remove_cvref_t<span class="op"><</span><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))>></span></code> is <code class="sourceCode cpp"><span class="kw">false</span></code>, <code class="sourceCode cpp">ranges<span class="op">::</span>rend<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. Otherwise,</span> <span class="rm" style="color: #bf0303"><del>The expression</del></span> <code class="sourceCode cpp">ranges<span class="op">::</span>rend<span class="op">(</span>E<span class="op">)</span></code> <span class="rm" style="color: #bf0303"><del>for some subexpression <span><code class="sourceCode cpp">E</code></span></del></span> is expression-equivalent to:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span> <span class="rm" style="color: #bf0303"><del>If <span><code class="sourceCode cpp">E</code></span> is an lvalue,</del></span> <code><i>decay-copy</i>(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>.rend())</code> if it is a valid expression and its type <code class="sourceCode cpp">S</code> models <code class="sourceCode cpp">sentinel_for<span class="op"><</span><span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">))></span></code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span> Otherwise, <code><i>decay-copy</i>(rend(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if it is a valid expression and its type <code class="sourceCode cpp">S</code> models <code class="sourceCode cpp">sentinel_for<span class="op"><</span><span class="kw">decltype</span><span class="op">(</span>ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">))></span></code>. with overload resolution performed in a context that includes the declaration:</p>
<div>
<div class="sourceCode" id="cb14"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb14-1"><a href="#cb14-1"></a>template<class T> void rend(T&&) = delete;</span></code></pre></div>
</div>
<p>and does not include a declaration of <code class="sourceCode cpp">ranges<span class="op">::</span>rend</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span> Otherwise, <code>make_reverse_iterator(ranges::begin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>))</code> if both <code>ranges::begin(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>)</code> and <code>ranges::end(<span class="rm" style="color: #bf0303"><del>E</del></span> <span class="addu">t</span>)</code> are valid expressions of the same type <code class="sourceCode cpp">I</code> which models <code class="sourceCode cpp">bidirectional_iterator</code> ([iterator.concept.bidir]).</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span> Otherwise, <code class="sourceCode cpp">ranges<span class="op">::</span>rend<span class="op">(</span>E<span class="op">)</span></code> is ill-formed. [ <em>Note</em>: This case can result in substitution failure when <code class="sourceCode cpp">ranges<span class="op">::</span>rend<span class="op">(</span>E<span class="op">)</span></code> appears in the immediate context of a template instantiation. — <em>end note</em> ]</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Note</em>: Whenever <code class="sourceCode cpp">ranges<span class="op">::</span>rend<span class="op">(</span>E<span class="op">)</span></code> is a valid expression, the types <code class="sourceCode cpp">S</code> and <code class="sourceCode cpp">I</code> of <code class="sourceCode cpp">ranges<span class="op">::</span>rend<span class="op">(</span>E<span class="op">)</span></code> and <code class="sourceCode cpp">ranges<span class="op">::</span>rbegin<span class="op">(</span>E<span class="op">)</span></code> model <code class="sourceCode cpp">sentinel_for<span class="op"><</span>S, I<span class="op">></span></code>. — <em>end note</em> ]</p>
</blockquote>
<p>Change 24.4.2 [range.range]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The <code class="sourceCode cpp">range</code> concept defines the requirements of a type that allows iteration over its elements by providing an iterator and sentinel that denote the elements of the range.</p>
<div>
<div class="sourceCode" id="cb15"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb15-1"><a href="#cb15-1"></a><span class="st">- template<class T></span></span>
<span id="cb15-2"><a href="#cb15-2"></a><span class="st">- concept range-impl = // exposition only</span></span>
<span id="cb15-3"><a href="#cb15-3"></a><span class="st">- requires(T&& t) {</span></span>
<span id="cb15-4"><a href="#cb15-4"></a><span class="st">- ranges::begin(std::forward<T>(t)); // sometimes equality-preserving (see below)</span></span>
<span id="cb15-5"><a href="#cb15-5"></a><span class="st">- ranges::end(std::forward<T>(t));</span></span>
<span id="cb15-6"><a href="#cb15-6"></a><span class="st">- };</span></span>
<span id="cb15-7"><a href="#cb15-7"></a><span class="st">- </span></span>
<span id="cb15-8"><a href="#cb15-8"></a><span class="st">- template<class T></span></span>
<span id="cb15-9"><a href="#cb15-9"></a><span class="st">- concept range = <em>range-impl</em><T&>;</span></span>
<span id="cb15-10"><a href="#cb15-10"></a><span class="st">- </span></span>
<span id="cb15-11"><a href="#cb15-11"></a><span class="st">- template<class T></span></span>
<span id="cb15-12"><a href="#cb15-12"></a><span class="st">- concept forwarding-range = // exposition only</span></span>
<span id="cb15-13"><a href="#cb15-13"></a><span class="st">- range<T> && range-impl<T>;</span></span>
<span id="cb15-14"><a href="#cb15-14"></a></span>
<span id="cb15-15"><a href="#cb15-15"></a><span class="va">+ template<class T></span></span>
<span id="cb15-16"><a href="#cb15-16"></a><span class="va">+ concept range =</span></span>
<span id="cb15-17"><a href="#cb15-17"></a><span class="va">+ requires(T& t) {</span></span>
<span id="cb15-18"><a href="#cb15-18"></a><span class="va">+ ranges::begin(t); // sometimes equality-preserving (see below)</span></span>
<span id="cb15-19"><a href="#cb15-19"></a><span class="va">+ ranges::end(t);</span></span>
<span id="cb15-20"><a href="#cb15-20"></a><span class="va">+ }; </span></span>
<span id="cb15-21"><a href="#cb15-21"></a><span class="va">+</span></span>
<span id="cb15-22"><a href="#cb15-22"></a><span class="va">+ template<class T></span></span>
<span id="cb15-23"><a href="#cb15-23"></a><span class="va">+ concept safe_range =</span></span>
<span id="cb15-24"><a href="#cb15-24"></a><span class="va">+ range<T> &&</span></span>
<span id="cb15-25"><a href="#cb15-25"></a><span class="va">+ (is_lvalue_reference_v<T> || enable_safe_range<remove_cvref_t<T>>);</span></span></code></pre></div>
</div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span> Given an expression <code class="sourceCode cpp">E</code> such that <code class="sourceCode cpp"><span class="kw">decltype</span><span class="op">((</span>E<span class="op">))</span></code> is <code class="sourceCode cpp">T</code> <span class="rm" style="color: #bf0303"><del>and an lvalue <span><code class="sourceCode cpp">t</code></span> that denotes the same object as <span><code class="sourceCode cpp">E</code></span></del></span>, <code class="sourceCode cpp">T</code> models <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span> only if <span class="addu">the validity of iterators obtained from the object denoted by <code class="sourceCode cpp">E</code> is not tied to the lifetime of that object.</span></p>
<div class="rm" style="color: #bf0303">
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>E<span class="op">)</span></code> and <code class="sourceCode cpp">ranges<span class="op">::</span>begin<span class="op">(</span>t<span class="op">)</span></code> are expression-equivalent,</li>
<li><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span> <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">(</span>E<span class="op">)</span></code> and <code class="sourceCode cpp">ranges<span class="op">::</span>end<span class="op">(</span>t<span class="op">)</span></code> are expression-equivalent, and</li>
<li><span class="marginalizedparent"><a class="marginalized">(5.3)</a></span> the validity of iterators obtained from the object denoted by <code class="sourceCode cpp">E</code> is not tied to the lifetime of that object.</li>
</ul>
</div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span> [ <em>Note</em>: Since the validity of iterators is not tied to the lifetime of an object whose type models <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span>, a function can accept arguments of such a type by value and return iterators obtained from it without danger of dangling. — <em>end note</em> ]</p>
<div>
<div class="sourceCode" id="cb16"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb16-1"><a href="#cb16-1"></a><span class="va">+ template<class></span></span>
<span id="cb16-2"><a href="#cb16-2"></a><span class="va">+ inline constexpr bool enable_safe_range = false;</span></span></code></pre></div>
</div>
<p><span class="marginalizedparent"><a class="marginalized">6*</a></span> <span class="addu"><em>Remarks</em>: Pursuant to [namespace.std], users may specialize <code class="sourceCode cpp">enable_safe_range</code> for <em>cv</em>-unqualified program-defined types. Such specializations shall be usable in constant expressions ([expr.const]) and have type <code class="sourceCode cpp"><span class="kw">const</span> <span class="dt">bool</span></code>.</span></p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span> [ Example: Specializations of class template <code class="sourceCode cpp">subrange</code> model <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span>. <code class="sourceCode cpp">subrange</code> <span class="rm" style="color: #bf0303"><del>provides non-member rvalue overloads of <span><code class="sourceCode cpp">begin</code></span> and <span><code class="sourceCode cpp">end</code></span> with the same semantics as its member lvalue overloads</del></span> <span class="addu">specializes <code class="sourceCode cpp">enable_safe_range</code> to <code class="sourceCode cpp"><span class="kw">true</span></code></span>, and <code class="sourceCode cpp">subrange</code>’s iterators - since they are “borrowed” from some other range - do not have validity tied to the lifetime of a subrange object. — <em>end example</em> ]</p>
</blockquote>
<p>Change 24.4.5 [range.refinements], the definition of the <code class="sourceCode cpp">viewable_range</code> concept:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span> The <code class="sourceCode cpp">viewable_range</code> concept specifies the requirements of a <code class="sourceCode cpp">range</code> type that can be converted to a <code class="sourceCode cpp">view</code> safely.</p>
<div>
<div class="sourceCode" id="cb17"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb17-1"><a href="#cb17-1"></a> template<class T></span>
<span id="cb17-2"><a href="#cb17-2"></a> concept viewable_range =</span>
<span id="cb17-3"><a href="#cb17-3"></a><span class="st">- range<T> && (<span class="diffdel"><em>forwarding-range</em></span><T> || view<decay_t<T>>);</span></span>
<span id="cb17-4"><a href="#cb17-4"></a><span class="va">+ range<T> && (<span class="diffins">safe_range</span><T> || view<decay_t<T>>);</span></span></code></pre></div>
</div>
</blockquote>
<p>Change 24.5.3 [range.subrange], to use <code class="sourceCode cpp">safe_range</code> instead of <em><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></em>, to remove the non-member <code class="sourceCode cpp">begin</code>/<code class="sourceCode cpp">end</code> overloads that were the old opt-in, and to add a specialization for <code class="sourceCode cpp">enable_safe_range</code> which is the new opt-in:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The <code class="sourceCode cpp">subrange</code> class template combines together an iterator and a sentinel into a single object that models the <code class="sourceCode cpp">view</code> concept. Additionally, it models the <code class="sourceCode cpp">sized_range</code> concept when the final template parameter is <code class="sourceCode cpp">subrange_kind<span class="op">::</span>sized</code>.</p>
<div>
<div class="sourceCode" id="cb18"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb18-1"><a href="#cb18-1"></a>namespace std::ranges {</span>
<span id="cb18-2"><a href="#cb18-2"></a></span>
<span id="cb18-3"><a href="#cb18-3"></a> template<input_or_output_iterator I, sentinel_for<I> S = I, subrange_kind K =</span>
<span id="cb18-4"><a href="#cb18-4"></a> sized_sentinel_for<S, I> ? subrange_kind::sized : subrange_kind::unsized></span>
<span id="cb18-5"><a href="#cb18-5"></a> requires (K == subrange_kind::sized || !sized_sentinel_for<S, I>)</span>
<span id="cb18-6"><a href="#cb18-6"></a> class subrange : public view_interface<subrange<I, S, K>> {</span>
<span id="cb18-7"><a href="#cb18-7"></a> </span>
<span id="cb18-8"><a href="#cb18-8"></a> template<<em>not-same-as</em><subrange> R></span>
<span id="cb18-9"><a href="#cb18-9"></a><span class="st">- requires <span class="diffdel"><em>forwarding-range</em></span><R> &&</span></span>
<span id="cb18-10"><a href="#cb18-10"></a><span class="va">+ requires <span class="diffins">safe_range</span><R> &&</span></span>
<span id="cb18-11"><a href="#cb18-11"></a> convertible_to<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S></span>
<span id="cb18-12"><a href="#cb18-12"></a> constexpr subrange(R&& r) requires (!StoreSize || sized_range<R>);</span>
<span id="cb18-13"><a href="#cb18-13"></a></span>
<span id="cb18-14"><a href="#cb18-14"></a><span class="st">- template<<span class="diffdel"><em>forwarding-range</em></span> R></span></span>
<span id="cb18-15"><a href="#cb18-15"></a><span class="va">+ template<<span class="diffins">safe_range</span> R></span></span>
<span id="cb18-16"><a href="#cb18-16"></a> requires convertible_to<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S></span>
<span id="cb18-17"><a href="#cb18-17"></a> constexpr subrange(R&& r, <em>make-unsigned-like-t</em>(iter_difference_t<I>) n)</span>
<span id="cb18-18"><a href="#cb18-18"></a> requires (K == subrange_kind::sized)</span>
<span id="cb18-19"><a href="#cb18-19"></a> : subrange{ranges::begin(r), ranges::end(r), n}</span>
<span id="cb18-20"><a href="#cb18-20"></a> {} </span>
<span id="cb18-21"><a href="#cb18-21"></a> </span>
<span id="cb18-22"><a href="#cb18-22"></a><span class="st">- friend constexpr I begin(subrange&& r) { return r.begin(); }</span></span>
<span id="cb18-23"><a href="#cb18-23"></a><span class="st">- friend constexpr S end(subrange&& r) { return r.end(); }</span></span>
<span id="cb18-24"><a href="#cb18-24"></a> };</span>
<span id="cb18-25"><a href="#cb18-25"></a></span>
<span id="cb18-26"><a href="#cb18-26"></a></span>
<span id="cb18-27"><a href="#cb18-27"></a><span class="st">- template<<span class="diffdel"><em>forwarding-range</em></span> R></span></span>
<span id="cb18-28"><a href="#cb18-28"></a><span class="va">+ template<<span class="diffins">safe_range</span> R></span></span>
<span id="cb18-29"><a href="#cb18-29"></a> subrange(R&&) -></span>
<span id="cb18-30"><a href="#cb18-30"></a> subrange<iterator_t<R>, sentinel_t<R>,</span>
<span id="cb18-31"><a href="#cb18-31"></a> (sized_range<R> || sized_sentinel_for<sentinel_t<R>, iterator_t<R>>)</span>
<span id="cb18-32"><a href="#cb18-32"></a> ? subrange_kind::sized : subrange_kind::unsized>;</span>
<span id="cb18-33"><a href="#cb18-33"></a></span>
<span id="cb18-34"><a href="#cb18-34"></a><span class="st">- template<<span class="diffdel"><em>forwarding-range</em></span> R></span></span>
<span id="cb18-35"><a href="#cb18-35"></a><span class="va">+ template<<span class="diffins">safe_range</span> R></span></span>
<span id="cb18-36"><a href="#cb18-36"></a> subrange(R&&, <em>make-unsigned-like-t</em>(range_difference_t<R>)) -></span>
<span id="cb18-37"><a href="#cb18-37"></a> subrange<iterator_t<R>, sentinel_t<R>, subrange_kind::sized>;</span>
<span id="cb18-38"><a href="#cb18-38"></a> </span>
<span id="cb18-39"><a href="#cb18-39"></a> template<size_t N, class I, class S, subrange_kind K></span>
<span id="cb18-40"><a href="#cb18-40"></a> requires (N < 2)</span>
<span id="cb18-41"><a href="#cb18-41"></a> constexpr auto get(const subrange<I, S, K>& r); </span>
<span id="cb18-42"><a href="#cb18-42"></a>}</span></code></pre></div>
</div>
</blockquote>
<p>Change the name of the concept in 24.5.3.1 [range.subrange.ctor]:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb19"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb19-1"><a href="#cb19-1"></a> template<<em>not-same-as</em><subrange> R></span>
<span id="cb19-2"><a href="#cb19-2"></a><span class="st">- requires <span class="diffdel"><em>forwarding-range</em></span><R> &&</span></span>
<span id="cb19-3"><a href="#cb19-3"></a><span class="va">+ requires <span class="diffins">safe_range</span><R> &&</span></span>
<span id="cb19-4"><a href="#cb19-4"></a> convertible_to<iterator_t<R>, I> && convertible_to<sentinel_t<R>, S></span>
<span id="cb19-5"><a href="#cb19-5"></a> constexpr subrange(R&& r) requires (!StoreSize || sized_range<R>);</span></code></pre></div>
</div>
</blockquote>
<p>Change the name of the concept in 24.5.4 [range.dangling]:</p>
<blockquote>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span> The tag type <code class="sourceCode cpp">dangling</code> is used together with the template aliases <code class="sourceCode cpp">safe_iterator_t</code> and <code class="sourceCode cpp">safe_subrange_t</code> to indicate that an algorithm that typically returns an iterator into or subrange of a <code class="sourceCode cpp">range</code> argument does not return an iterator or subrange which could potentially reference a range whose lifetime has ended for a particular rvalue <code class="sourceCode cpp">range</code> argument which does not model <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span> ([range.range]).</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span> [ <em>Example</em>: […]</p>
<p>The call to <code class="sourceCode cpp">ranges<span class="op">::</span>find</code> at <code class="sourceCode cpp"><span class="pp">#1</span></code> returns <code class="sourceCode cpp">ranges<span class="op">::</span>dangling</code> since <code class="sourceCode cpp">f<span class="op">()</span></code> is an rvalue <code class="sourceCode cpp">vector</code>; the <code class="sourceCode cpp">vector</code> could potentially be destroyed before a returned iterator is dereferenced. However, the calls at <code class="sourceCode cpp"><span class="pp">#2</span></code> and <code class="sourceCode cpp"><span class="pp">#3</span></code> both return iterators since the lvalue vec and specializations of <code class="sourceCode cpp">subrange</code> model <span class="rm" style="color: #bf0303"><del><em><span><code class="sourceCode cpp">forwarding<span class="op">-</span>range</code></span></em></del></span> <span class="addu"><code class="sourceCode cpp">safe_range</code></span>. — <em>end example</em> ]</p>
</blockquote>
<p>Remove the non-member old opt-ins in 24.6.1.2 [range.empty.view]:</p>
<blockquote>
<div>
<div class="sourceCode" id="cb20"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb20-1"><a href="#cb20-1"></a>namespace std::ranges {</span>
<span id="cb20-2"><a href="#cb20-2"></a> template<class T></span>
<span id="cb20-3"><a href="#cb20-3"></a> requires is_object_v<T></span>
<span id="cb20-4"><a href="#cb20-4"></a> class empty_view : public view_interface<empty_view<T>> {</span>
<span id="cb20-5"><a href="#cb20-5"></a> public:</span>
<span id="cb20-6"><a href="#cb20-6"></a></span>