Skip to content

Commit 8ea4c3d

Browse files
committed
any_view wording : address Sofia SG9 meeting comments
1 parent f12099e commit 8ea4c3d

File tree

1 file changed

+59
-41
lines changed

1 file changed

+59
-41
lines changed

any_view.md

Lines changed: 59 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ toc-depth: 2
1818

1919
# Revision History
2020

21+
## R4
22+
23+
- Default constructed and moved-from object will be assigned to an empty view
24+
2125
## R3
2226

2327
- Fix `contiguous` range
@@ -566,6 +570,19 @@ We propose providing the strong exception safety guarantee in the following oper
566570
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.
567571
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.
568572
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+
569586
## ABI Stability
570587

571588
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 {
933950
class @*sentinel*@; // exposition-only
934951
public:
935952
// [range.any.ctor], constructors, assignment, and destructor
953+
constexpr any_view();
936954
template <class Rng> constexpr any_view(Rng&& rng);
937955
constexpr any_view(const any_view&);
938956
constexpr any_view(any_view&&) noexcept;
@@ -1019,54 +1037,60 @@ constexpr bool @*any-view-flag-is-set*@(any_view_options opts, any_view_options
10191037

10201038
#### ?.?.?.4 Constructors, assignment, and destructor [range.any.ctor] {-}
10211039

1040+
```cpp
1041+
constexpr any_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+
10221050
```cpp
10231051
template <class Rng> constexpr any_view(Rng&& rng);
10241052
```
10251053
10261054
:::bq
10271055
1028-
[1]{.pnum} *Constraints*:
1056+
[2]{.pnum} *Constraints*:
10291057
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
10311059
1032-
- [1.2]{.pnum} `Rng` models `viewable_range`, and
1060+
- [2.2]{.pnum} `Rng` models `viewable_range`, and
10331061
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`
10351063
models `sized_range`, and
10361064
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`
10381066
models `borrowed_range`, and
10391067
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>`
10411069
models `copyable`, and
10421070
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
10481072
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
10501074
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
10521076
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
10541078
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>`,
10561080
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`
10581082
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`,
10601084
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`,
10621086
1063-
[2]{.pnum} *Postconditions*:
1087+
- [2.10.4]{.pnum} Otherwise if `CAT` is `any_views_options::forward`, `R` models `forward_range`,
10641088
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`
10661090
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)`.
10681092
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`.
10701094
10711095
:::
10721096
@@ -1076,9 +1100,9 @@ constexpr any_view(const any_view& other);
10761100

10771101
:::bq
10781102

1079-
[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`
10801104

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`.
10821106

10831107
:::
10841108

@@ -1088,7 +1112,7 @@ constexpr any_view(any_view&& other) noexcept;
10881112
10891113
:::bq
10901114
1091-
[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`
10921116
10931117
:::
10941118
@@ -1098,11 +1122,11 @@ constexpr any_view &operator=(const any_view& other)
10981122

10991123
:::bq
11001124

1101-
[7]{.pnum} *Constraints*: `Opts & any_view_options::copyable` is `any_view_options::copyable`
1125+
[8]{.pnum} *Constraints*: `Opts & any_view_options::copyable` is `any_view_options::copyable`
11021126

1103-
[8]{.pnum} *Effects*: Equivalent to: `any_view(other).swap(*this);`
1127+
[9]{.pnum} *Effects*: Equivalent to: `any_view(other).swap(*this);`
11041128

1105-
[9]{.pnum} *Returns*: `*this`.
1129+
[10]{.pnum} *Returns*: `*this`.
11061130

11071131
:::
11081132

@@ -1112,9 +1136,9 @@ constexpr any_view &operator=(any_view&& other)
11121136

11131137
:::bq
11141138

1115-
[10]{.pnum} *Effects*: Equivalent to: `any_view(std::move(other)).swap(*this);`
1139+
[11]{.pnum} *Effects*: Equivalent to: `any_view(std::move(other)).swap(*this);`
11161140

1117-
[11]{.pnum} *Returns*: `*this`.
1141+
[12]{.pnum} *Returns*: `*this`.
11181142

11191143
:::
11201144

@@ -1124,7 +1148,7 @@ constexpr ~any_view();
11241148

11251149
:::bq
11261150

1127-
[12]{.pnum} *Effects*: Destroys the *target view object* of `*this`, if any.
1151+
[13]{.pnum} *Effects*: Destroys the *target view object* of `*this`.
11281152

11291153
:::
11301154

@@ -1136,9 +1160,7 @@ constexpr @*iterator*@ begin();
11361160

11371161
:::bq
11381162

1139-
[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)`
11421164

11431165
:::
11441166

@@ -1148,9 +1170,7 @@ constexpr @*sentinel*@ end();
11481170

11491171
:::bq
11501172

1151-
[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)`
11541174

11551175
:::
11561176

@@ -1160,11 +1180,9 @@ constexpr @*make-unsigned-like-t*@<Diff> size() const;
11601180

11611181
:::bq
11621182

1163-
[5]{.pnum} *Constraints*: `Opts & any_view_options::sized` is `any_view_options::sized`
1164-
1165-
[6]{.pnum} *Preconditions*: `*this` has a *target view object*.
1183+
[3]{.pnum} *Constraints*: `Opts & any_view_options::sized` is `any_view_options::sized`
11661184

1167-
[7]{.pnum} *Effects*: Equivalent to:
1185+
[4]{.pnum} *Effects*: Equivalent to:
11681186

11691187
```cpp
11701188
return @*make-unsigned-like-t*@<Diff>(ranges::size(v));

0 commit comments

Comments
 (0)