You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: any_view.md
+59-41Lines changed: 59 additions & 41 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,10 @@ toc-depth: 2
18
18
19
19
# Revision History
20
20
21
+
## R4
22
+
23
+
- Default constructed and moved-from object will be assigned to an empty view
24
+
21
25
## R3
22
26
23
27
- Fix `contiguous` range
@@ -566,6 +570,19 @@ We propose providing the strong exception safety guarantee in the following oper
566
570
If the underlying view's move constructor (or move-assignment operator) is not `noexcept`, the only way to achieve the strong exception safety guarantee is to avoid calling these operations altogether, which requires `any_view` to hold its underlying object on the heap so it can implement these operations by swapping pointers.
567
571
This means that any implementation of `any_view` will have an empty state, and a "moved-from" heap allocated `any_view` will be in that state.
568
572
573
+
In the original design, we proposed any operations, other than assignment or destruction, have preconditions that the `any_view` is not in an empty state. This allows implementations to leave the moved-from object containing a `nullptr` if the wrapped object is heap allocated. However, in Sofia meeting, SG9 has decided that the moved-from object should behave like an empty view.
574
+
575
+
> The moved-from state of `std::ranges::any_view` should behave like it contains an empty view with the specified properties. `begin()` always return an `iterator` (and doesn't have a precondition).
576
+
577
+
|SF |F |N |A |SA|
578
+
|---|---|---|---|--|
579
+
|5 |2 |0 |2 |0 |
580
+
581
+
This revision (R4) follows SG9's recommendation to make the moved-from state as an empty view. However, the authors still believe that this is a wrong decision.
582
+
This is an unprecedented design in the standard library type erasure facilities. We did not make `std::any` to assign an empty `struct` to a moved-from object.
583
+
We did not make `std::{copyable_,move_only}function<void()>` to assign `[]{}` to a moved-from object. This is adding unnecessary complexity. Instead, we should
584
+
just discourage people from using the moved-from object other than destruction or assignment.
585
+
569
586
## ABI Stability
570
587
571
588
As a type intended to exist at ABI boundaries, ensuring the ABI stability of `any_view` is extremely important. However, since almost any change to the API of `any_view` will require a modification to the vtable, this makes `any_view` somewhat fragile to incremental evolution.
@@ -933,6 +950,7 @@ class any_view {
933
950
class @*sentinel*@; // exposition-only
934
951
public:
935
952
// [range.any.ctor], constructors, assignment, and destructor
#### ?.?.?.4 Constructors, assignment, and destructor [range.any.ctor] {-}
1021
1039
1040
+
```cpp
1041
+
constexprany_view();
1042
+
```
1043
+
1044
+
:::bq
1045
+
1046
+
[1]{.pnum} *Postconditions*: `*this` holds a *target view object*`v`, where `ranges::empty(v)` is `true`.
1047
+
1048
+
:::
1049
+
1022
1050
```cpp
1023
1051
template <classRng> constexprany_view(Rng&& rng);
1024
1052
```
1025
1053
1026
1054
:::bq
1027
1055
1028
-
[1]{.pnum} *Constraints*:
1056
+
[2]{.pnum} *Constraints*:
1029
1057
1030
-
- [1.1]{.pnum} `remove_cvref_t<Rng>` is not the same type as `any_view`, and
1058
+
- [2.1]{.pnum} `remove_cvref_t<Rng>` is not the same type as `any_view`, and
1031
1059
1032
-
- [1.2]{.pnum} `Rng` models `viewable_range`, and
1060
+
- [2.2]{.pnum} `Rng` models `viewable_range`, and
1033
1061
1034
-
- [1.3]{.pnum} either `@*any-view-flag-is-set*@(Opts, any_view_options::sized)` is `false`, or `Rng`
1062
+
- [2.3]{.pnum} either `@*any-view-flag-is-set*@(Opts, any_view_options::sized)` is `false`, or `Rng`
1035
1063
models `sized_range`, and
1036
1064
1037
-
- [1.4]{.pnum} either `@*any-view-flag-is-set*@(Opts, any_view_options::borrowed)` is `false`, or `Rng`
1065
+
- [2.4]{.pnum} either `@*any-view-flag-is-set*@(Opts, any_view_options::borrowed)` is `false`, or `Rng`
1038
1066
models `borrowed_range`, and
1039
1067
1040
-
- [1.5]{.pnum} either `@*any-view-flag-is-set*@(Opts, any_view_options::copyable)` is `false`, or `all_t<Rng>`
1068
+
- [2.5]{.pnum} either `@*any-view-flag-is-set*@(Opts, any_view_options::copyable)` is `false`, or `all_t<Rng>`
1041
1069
models `copyable`, and
1042
1070
1043
-
- [1.6]{.pnum} `is_convertible_v<range_reference_t<all_t<Rng>>, Ref>` is `true`, and
1044
-
1045
-
- [1.7]{.pnum} `is_convertible_v<range_value_t<all_t<Rng>>, remove_cv_t<Element>>` is `true`, and
1046
-
1047
-
- [1.8]{.pnum} `is_convertible_v<range_rvalue_reference_t<all_t<Rng>>, RValueRef>` is `true`, and
1071
+
- [2.6]{.pnum} `is_convertible_v<range_reference_t<all_t<Rng>>, Ref>` is `true`, and
1048
1072
1049
-
- [1.9]{.pnum} `is_convertible_v<range_difference_t<all_t<Rng>>, Diff>` is `true`, and
1073
+
- [2.7]{.pnum} `is_convertible_v<range_value_t<all_t<Rng>>, remove_cv_t<Element>>` is `true`, and
1050
1074
1051
-
- [1.10]{.pnum} Let `CAT` be `Opts & any_view_options::contiguous`, `R` be `all_t<Rng>`,
1075
+
- [2.8]{.pnum} `is_convertible_v<range_rvalue_reference_t<all_t<Rng>>, RValueRef>` is `true`, and
1052
1076
1053
-
- [1.10.1]{.pnum} If `CAT` is `any_views_options::contiguous`, `R` models `contiguous_range`
1077
+
- [2.9]{.pnum} `is_convertible_v<range_difference_t<all_t<Rng>>, Diff>` is `true`, and
1054
1078
1055
-
- [1.10.2]{.pnum} Otherwise, if `CAT` is `any_views_options::random_access`, `R` models `random_access_range`,
1079
+
- [2.10]{.pnum} Let `CAT` be `Opts & any_view_options::contiguous`, `R` be `all_t<Rng>`,
1056
1080
1057
-
- [1.10.3]{.pnum} Otherwise, if `CAT` is `any_views_options::bidirectional`, `R` models `bidirectional_range`,
1081
+
- [2.10.1]{.pnum} If `CAT` is `any_views_options::contiguous`, `R` models `contiguous_range`
1058
1082
1059
-
- [1.10.4]{.pnum} Otherwise if `CAT` is `any_views_options::forward`, `R` models `forward_range`,
1083
+
- [2.10.2]{.pnum} Otherwise, if `CAT` is `any_views_options::random_access`, `R` models `random_access_range`,
1060
1084
1061
-
- [1.10.5]{.pnum} Otherwise, `CAT` is `any_views_options::input`, and `R` models `input_range`
1085
+
- [2.10.3]{.pnum} Otherwise, if `CAT` is `any_views_options::bidirectional`, `R` models `bidirectional_range`,
1062
1086
1063
-
[2]{.pnum} *Postconditions*:
1087
+
- [2.10.4]{.pnum} Otherwise if `CAT` is `any_views_options::forward`, `R` models `forward_range`,
1064
1088
1065
-
- [2.1]{.pnum} `*this` has no *target view object* if `remove_cvref_t<Rng>` is a specialization of the `any_view` class template, and `rng` has no *target view object*.
1089
+
- [2.10.5]{.pnum} Otherwise, `CAT` is `any_views_options::input`, and `R` models `input_range`
1066
1090
1067
-
- [2.2]{.pnum} Otherwise, `*this` has a *target view object* of type `all_t<Rng>` direct-non-list-initialized with `std::forward<Rng>(rng)`.
1091
+
[3]{.pnum} *Postconditions*: `*this` has a *target view object* of type `all_t<Rng>` direct-non-list-initialized with `std::forward<Rng>(rng)`.
1068
1092
1069
-
[3]{.pnum} *Throws*: Any exception thrown by the initialization of the *target view object*. May throw `bad_alloc`.
1093
+
[4]{.pnum} *Throws*: Any exception thrown by the initialization of the *target view object*. May throw `bad_alloc`.
[4]{.pnum} *Constraints*: `Opts & any_view_options::copyable` is `any_view_options::copyable`
1103
+
[5]{.pnum} *Constraints*: `Opts & any_view_options::copyable` is `any_view_options::copyable`
1080
1104
1081
-
[5]{.pnum} *Postconditions*: `*this` has no *target view object* if `other` had no *target view object*. Otherwise, the*target view object* of `*this` is a copy of the *target view object* of `other`.
1105
+
[6]{.pnum} *Postconditions*: The*target view object* of `*this` is a copy of the *target view object* of `other`.
[6]{.pnum} *Postconditions*: `*this` has no *target view object* if `other` had no *target view object*. Otherwise, the *target view object* of `*this` is equivalent to the *target view object* of `other` before the construction of `*this`, and `other` is in a valid state with an unspecified value.
1115
+
[7]{.pnum} *Postconditions*: The *target view object* of `*this` is equivalent to the *target view object* of `other` before the construction of `*this`, and `other` holds a *target view object* `v` where `ranges::empty(v)` is `true`
[1]{.pnum} *Preconditions*: `*this` has a *target view object*.
1140
-
1141
-
[2]{.pnum} *Effects*: Let `v` be an lvalue designating the *target view object* of `*this`, returns an object of *iterator wrapper type*`@*iterator*@`, which holds a *target iterator object* of `ranges::begin(v)`
1163
+
[1]{.pnum} *Effects*: Let `v` be an lvalue designating the *target view object* of `*this`, returns an object of *iterator wrapper type*`@*iterator*@`, which holds a *target iterator object* of `ranges::begin(v)`
[3]{.pnum} *Preconditions*: `*this` has a *target view object*.
1152
-
1153
-
[4]{.pnum} *Effects*: Let `v` be an lvalue designating the *target view object* of `*this`, returns an object of *sentinel wrapper type*`@*sentinel*@`, which holds a *target sentinel object* of `ranges::end(v)`
1173
+
[2]{.pnum} *Effects*: Let `v` be an lvalue designating the *target view object* of `*this`, returns an object of *sentinel wrapper type*`@*sentinel*@`, which holds a *target sentinel object* of `ranges::end(v)`
0 commit comments