From Jason Turner

[range.join]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp7l8brh45/{from.md → to.md} +128 -91
tmp/tmp7l8brh45/{from.md → to.md} RENAMED
@@ -1,66 +1,74 @@
1
  ### Join view <a id="range.join">[[range.join]]</a>
2
 
3
  #### Overview <a id="range.join.overview">[[range.join.overview]]</a>
4
 
5
- `join_view` flattens a `view` of ranges into a `view`.
6
 
7
  The name `views::join` denotes a range adaptor object
8
  [[range.adaptor.object]]. Given a subexpression `E`, the expression
9
- `views::join(E)` is expression-equivalent to `join_view{E}`.
 
10
 
11
  [*Example 1*:
12
 
13
  ``` cpp
14
  vector<string> ss{"hello", " ", "world", "!"};
15
- join_view greeting{ss};
16
- for (char ch : greeting)
17
- cout << ch; // prints: hello world!
18
  ```
19
 
20
  — *end example*]
21
 
22
  #### Class template `join_view` <a id="range.join.view">[[range.join.view]]</a>
23
 
24
  ``` cpp
25
  namespace std::ranges {
26
  template<input_range V>
27
- requires view<V> && input_range<range_reference_t<V>> &&
28
- (is_reference_v<range_reference_t<V>> ||
29
- view<range_value_t<V>>)
30
  class join_view : public view_interface<join_view<V>> {
31
  private:
32
- using InnerRng = // exposition only
33
- range_reference_t<V>;
34
  // [range.join.iterator], class template join_view::iterator
35
  template<bool Const>
36
  struct iterator; // exposition only
 
37
  // [range.join.sentinel], class template join_view::sentinel
38
  template<bool Const>
39
  struct sentinel; // exposition only
40
 
41
  V base_ = V(); // exposition only
42
- views::all_t<InnerRng> inner_ = // exposition only, present only when !is_reference_v<InnerRng>
43
- views::all_t<InnerRng>();
 
 
 
 
44
  public:
45
- join_view() = default;
46
  constexpr explicit join_view(V base);
47
 
48
  constexpr V base() const & requires copy_constructible<V> { return base_; }
49
  constexpr V base() && { return std::move(base_); }
50
 
51
  constexpr auto begin() {
 
52
  constexpr bool use_const = simple-view<V> &&
53
- is_reference_v<range_reference_t<V>>;
54
  return iterator<use_const>{*this, ranges::begin(base_)};
 
 
 
 
55
  }
56
 
57
  constexpr auto begin() const
58
- requires input_range<const V> &&
59
- is_reference_v<range_reference_t<const V>> {
60
- return iterator<true>{*this, ranges::begin(base_)};
61
- }
62
 
63
  constexpr auto end() {
64
  if constexpr (forward_range<V> &&
65
  is_reference_v<InnerRng> && forward_range<InnerRng> &&
66
  common_range<V> && common_range<InnerRng>)
@@ -68,15 +76,14 @@ namespace std::ranges {
68
  else
69
  return sentinel<simple-view<V>>{*this};
70
  }
71
 
72
  constexpr auto end() const
73
- requires input_range<const V> &&
74
- is_reference_v<range_reference_t<const V>> {
75
- if constexpr (forward_range<const V> &&
76
  is_reference_v<range_reference_t<const V>> &&
77
- forward_range<range_reference_t<const V>> &&
 
78
  common_range<const V> &&
79
  common_range<range_reference_t<const V>>)
80
  return iterator<true>{*this, ranges::end(base_)};
81
  else
82
  return sentinel<true>{*this};
@@ -97,47 +104,53 @@ constexpr explicit join_view(V base);
97
  #### Class template `join_view::iterator` <a id="range.join.iterator">[[range.join.iterator]]</a>
98
 
99
  ``` cpp
100
  namespace std::ranges {
101
  template<input_range V>
102
- requires view<V> && input_range<range_reference_t<V>> &&
103
- (is_reference_v<range_reference_t<V>> ||
104
- view<range_value_t<V>>)
105
  template<bool Const>
106
  struct join_view<V>::iterator {
107
  private:
108
- using Parent = // exposition only
109
- conditional_t<Const, const join_view, join_view>;
110
- using Base = conditional_t<Const, const V, V>; // exposition only
 
111
 
112
  static constexpr bool ref-is-glvalue = // exposition only
113
  is_reference_v<range_reference_t<Base>>;
114
 
115
- iterator_t<Base> outer_ = iterator_t<Base>(); // exposition only
116
- iterator_t<range_reference_t<Base>> inner_ = // exposition only
117
- iterator_t<range_reference_t<Base>>();
118
  Parent* parent_ = nullptr; // exposition only
119
 
120
  constexpr void satisfy(); // exposition only
 
 
 
 
 
 
 
 
 
121
  public:
122
  using iterator_concept = see below;
123
- using iterator_category = see below;
124
  using value_type = range_value_t<range_reference_t<Base>>;
125
  using difference_type = see below;
126
 
127
  iterator() = default;
128
- constexpr iterator(Parent& parent, iterator_t<Base> outer);
129
  constexpr iterator(iterator<!Const> i)
130
  requires Const &&
131
- convertible_to<iterator_t<V>, iterator_t<Base>> &&
132
- convertible_to<iterator_t<InnerRng>,
133
- iterator_t<range_reference_t<Base>>>;
134
 
135
- constexpr decltype(auto) operator*() const { return *inner_; }
136
 
137
- constexpr iterator_t<Base> operator->() const
138
- requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>;
139
 
140
  constexpr iterator& operator++();
141
  constexpr void operator++(int);
142
  constexpr iterator operator++(int)
143
  requires ref-is-glvalue && forward_range<Base> &&
@@ -152,50 +165,53 @@ namespace std::ranges {
152
  requires ref-is-glvalue && bidirectional_range<Base> &&
153
  bidirectional_range<range_reference_t<Base>> &&
154
  common_range<range_reference_t<Base>>;
155
 
156
  friend constexpr bool operator==(const iterator& x, const iterator& y)
157
- requires ref-is-glvalue && equality_comparable<iterator_t<Base>> &&
158
  equality_comparable<iterator_t<range_reference_t<Base>>>;
159
 
160
  friend constexpr decltype(auto) iter_move(const iterator& i)
161
- noexcept(noexcept(ranges::iter_move(i.inner_))) {
162
- return ranges::iter_move(i.inner_);
163
  }
164
 
165
  friend constexpr void iter_swap(const iterator& x, const iterator& y)
166
- noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_)));
 
167
  };
168
  }
169
  ```
170
 
171
  `iterator::iterator_concept` is defined as follows:
172
 
173
- - If *`ref-is-glvalue`* is `true` and *`Base`* and
174
- `range_reference_t<Base>` each model `bidirectional_range`, then
175
- `iterator_concept` denotes `bidirectional_iterator_tag`.
 
176
  - Otherwise, if *`ref-is-glvalue`* is `true` and *`Base`* and
177
  `range_reference_t<Base>` each model , then `iterator_concept` denotes
178
  `forward_iterator_tag`.
179
  - Otherwise, `iterator_concept` denotes `input_iterator_tag`.
180
 
 
 
 
181
  `iterator::iterator_category` is defined as follows:
182
 
183
  - Let *OUTERC* denote
184
  `iterator_traits<iterator_t<Base>>::iterator_category`, and let
185
  *INNERC* denote
186
  `iterator_traits<iterator_t<range_reference_t<Base>>>::iterator_category`.
187
- - If *`ref-is-glvalue`* is `true` and *OUTERC* and *INNERC* each model
188
- `derived_from<bidirectional_iterator_tag>`, `iterator_category`
 
189
  denotes `bidirectional_iterator_tag`.
190
- - Otherwise, if *`ref-is-glvalue`* is `true` and *OUTERC* and *INNERC*
191
- each model `derived_from<forward_iterator_tag>`, `iterator_category`
192
- denotes `forward_iterator_tag`.
193
  - Otherwise, if *OUTERC* and *INNERC* each model
194
- `derived_from<input_iterator_tag>`, `iterator_category` denotes
195
- `input_iterator_tag`.
196
- - Otherwise, `iterator_category` denotes `output_iterator_tag`.
197
 
198
  `iterator::difference_type` denotes the type:
199
 
200
  ``` cpp
201
  common_type_t<
@@ -205,74 +221,92 @@ common_type_t<
205
 
206
  `join_view` iterators use the *`satisfy`* function to skip over empty
207
  inner ranges.
208
 
209
  ``` cpp
210
- constexpr void satisfy(); // exposition only
 
 
 
 
 
 
 
 
211
  ```
212
 
213
  *Effects:* Equivalent to:
214
 
215
  ``` cpp
216
- auto update_inner = [this](range_reference_t<Base> x) -> auto& {
217
- if constexpr (ref-is-glvalue) // x is a reference
218
- return x;
219
  else
220
- return (parent_->inner_ = views::all(std::move(x)));
221
  };
222
 
223
- for (; outer_ != ranges::end(parent_->base_); ++outer_) {
224
- auto& inner = update_inner(*outer_);
225
  inner_ = ranges::begin(inner);
226
- if (inner_ != ranges::end(inner))
227
  return;
228
  }
229
  if constexpr (ref-is-glvalue)
230
- inner_ = iterator_t<range_reference_t<Base>>();
231
  ```
232
 
233
  ``` cpp
234
- constexpr iterator(Parent& parent, iterator_t<Base> outer);
 
235
  ```
236
 
237
  *Effects:* Initializes *outer\_* with `std::move(outer)` and *parent\_*
238
  with `addressof(parent)`; then calls *`satisfy`*`()`.
239
 
 
 
 
 
 
 
 
 
240
  ``` cpp
241
  constexpr iterator(iterator<!Const> i)
242
  requires Const &&
243
- convertible_to<iterator_t<V>, iterator_t<Base>> &&
244
- convertible_to<iterator_t<InnerRng>,
245
- iterator_t<range_reference_t<Base>>>;
246
  ```
247
 
248
  *Effects:* Initializes *outer\_* with `std::move(i.`*`outer_`*`)`,
249
  *inner\_* with `std::move(i.`*`inner_`*`)`, and *parent\_* with
250
  `i.`*`parent_`*.
251
 
 
 
 
252
  ``` cpp
253
- constexpr iterator_t<Base> operator->() const
254
- requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>;
255
  ```
256
 
257
- *Effects:* Equivalent to `return `*`inner_`*`;`
258
 
259
  ``` cpp
260
  constexpr iterator& operator++();
261
  ```
262
 
263
  Let *`inner-range`* be:
264
 
265
- - If *ref-is-glvalue* is `true`, `*`*`outer_`*.
266
- - Otherwise, *`parent_`*`->`*`inner_`*.
267
 
268
  *Effects:* Equivalent to:
269
 
270
  ``` cpp
271
- auto&& inner_rng = inner-range;
272
- if (++inner_ == ranges::end(inner_rng)) {
273
- ++outer_;
274
  satisfy();
275
  }
276
  return *this;
277
  ```
278
 
@@ -305,14 +339,14 @@ constexpr iterator& operator--()
305
 
306
  *Effects:* Equivalent to:
307
 
308
  ``` cpp
309
  if (outer_ == ranges::end(parent_->base_))
310
- inner_ = ranges::end(*--outer_);
311
- while (inner_ == ranges::begin(*outer_))
312
- inner_ = ranges::end(*--outer_);
313
- --inner_;
314
  return *this;
315
  ```
316
 
317
  ``` cpp
318
  constexpr iterator operator--(int)
@@ -329,48 +363,49 @@ auto tmp = *this;
329
  return tmp;
330
  ```
331
 
332
  ``` cpp
333
  friend constexpr bool operator==(const iterator& x, const iterator& y)
334
- requires ref-is-glvalue && equality_comparable<iterator_t<Base>> &&
335
  equality_comparable<iterator_t<range_reference_t<Base>>>;
336
  ```
337
 
338
  *Effects:* Equivalent to:
339
  `return x.`*`outer_`*` == y.`*`outer_`*` && x.`*`inner_`*` == y.`*`inner_`*`;`
340
 
341
  ``` cpp
342
  friend constexpr void iter_swap(const iterator& x, const iterator& y)
343
- noexcept(noexcept(ranges::iter_swap(x.inner_, y.inner_)));
 
344
  ```
345
 
346
  *Effects:* Equivalent to:
347
- `return ranges::iter_swap(x.`*`inner_`*`, y.`*`inner_`*`);`
348
 
349
  #### Class template `join_view::sentinel` <a id="range.join.sentinel">[[range.join.sentinel]]</a>
350
 
351
  ``` cpp
352
  namespace std::ranges {
353
  template<input_range V>
354
- requires view<V> && input_range<range_reference_t<V>> &&
355
- (is_reference_v<range_reference_t<V>> ||
356
- view<range_value_t<V>>)
357
  template<bool Const>
358
  struct join_view<V>::sentinel {
359
  private:
360
- using Parent = // exposition only
361
- conditional_t<Const, const join_view, join_view>;
362
- using Base = conditional_t<Const, const V, V>; // exposition only
363
  sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition only
 
364
  public:
365
  sentinel() = default;
366
 
367
  constexpr explicit sentinel(Parent& parent);
368
  constexpr sentinel(sentinel<!Const> s)
369
  requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
370
 
371
- friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);
 
 
372
  };
373
  }
374
  ```
375
 
376
  ``` cpp
@@ -385,10 +420,12 @@ constexpr sentinel(sentinel<!Const> s)
385
  ```
386
 
387
  *Effects:* Initializes *end\_* with `std::move(s.`*`end_`*`)`.
388
 
389
  ``` cpp
390
- friend constexpr bool operator==(const iterator<Const>& x, const sentinel& y);
 
 
391
  ```
392
 
393
- *Effects:* Equivalent to: `return x.`*`outer_`*` == y.`*`end_`*`;`
394
 
 
1
  ### Join view <a id="range.join">[[range.join]]</a>
2
 
3
  #### Overview <a id="range.join.overview">[[range.join.overview]]</a>
4
 
5
+ `join_view` flattens a view of ranges into a view.
6
 
7
  The name `views::join` denotes a range adaptor object
8
  [[range.adaptor.object]]. Given a subexpression `E`, the expression
9
+ `views::join(E)` is expression-equivalent to
10
+ `join_view<views::all_t<decltype((E))>>{E}`.
11
 
12
  [*Example 1*:
13
 
14
  ``` cpp
15
  vector<string> ss{"hello", " ", "world", "!"};
16
+ for (char ch : ss | views::join)
17
+ cout << ch; // prints hello world!
 
18
  ```
19
 
20
  — *end example*]
21
 
22
  #### Class template `join_view` <a id="range.join.view">[[range.join.view]]</a>
23
 
24
  ``` cpp
25
  namespace std::ranges {
26
  template<input_range V>
27
+ requires view<V> && input_range<range_reference_t<V>>
 
 
28
  class join_view : public view_interface<join_view<V>> {
29
  private:
30
+ using InnerRng = range_reference_t<V>; // exposition only
31
+
32
  // [range.join.iterator], class template join_view::iterator
33
  template<bool Const>
34
  struct iterator; // exposition only
35
+
36
  // [range.join.sentinel], class template join_view::sentinel
37
  template<bool Const>
38
  struct sentinel; // exposition only
39
 
40
  V base_ = V(); // exposition only
41
+
42
+ non-propagating-cache<iterator_t<V>> outer_; // exposition only, present only
43
+ // when !forward_range<V>
44
+ non-propagating-cache<remove_cv_t<InnerRng>> inner_; // exposition only, present only
45
+ // if is_reference_v<InnerRng> is false
46
+
47
  public:
48
+ join_view() requires default_initializable<V> = default;
49
  constexpr explicit join_view(V base);
50
 
51
  constexpr V base() const & requires copy_constructible<V> { return base_; }
52
  constexpr V base() && { return std::move(base_); }
53
 
54
  constexpr auto begin() {
55
+ if constexpr (forward_range<V>) {
56
  constexpr bool use_const = simple-view<V> &&
57
+ is_reference_v<InnerRng>;
58
  return iterator<use_const>{*this, ranges::begin(base_)};
59
+ } else {
60
+ outer_ = ranges::begin(base_);
61
+ return iterator<false>{*this};
62
+ }
63
  }
64
 
65
  constexpr auto begin() const
66
+ requires forward_range<const V> &&
67
+ is_reference_v<range_reference_t<const V>> &&
68
+ input_range<range_reference_t<const V>>
69
+ { return iterator<true>{*this, ranges::begin(base_)}; }
70
 
71
  constexpr auto end() {
72
  if constexpr (forward_range<V> &&
73
  is_reference_v<InnerRng> && forward_range<InnerRng> &&
74
  common_range<V> && common_range<InnerRng>)
 
76
  else
77
  return sentinel<simple-view<V>>{*this};
78
  }
79
 
80
  constexpr auto end() const
81
+ requires forward_range<const V> &&
 
 
82
  is_reference_v<range_reference_t<const V>> &&
83
+ input_range<range_reference_t<const V>> {
84
+ if constexpr (forward_range<range_reference_t<const V>> &&
85
  common_range<const V> &&
86
  common_range<range_reference_t<const V>>)
87
  return iterator<true>{*this, ranges::end(base_)};
88
  else
89
  return sentinel<true>{*this};
 
104
  #### Class template `join_view::iterator` <a id="range.join.iterator">[[range.join.iterator]]</a>
105
 
106
  ``` cpp
107
  namespace std::ranges {
108
  template<input_range V>
109
+ requires view<V> && input_range<range_reference_t<V>>
 
 
110
  template<bool Const>
111
  struct join_view<V>::iterator {
112
  private:
113
+ using Parent = maybe-const<Const, join_view>; // exposition only
114
+ using Base = maybe-const<Const, V>; // exposition only
115
+ using OuterIter = iterator_t<Base>; // exposition only
116
+ using InnerIter = iterator_t<range_reference_t<Base>>; // exposition only
117
 
118
  static constexpr bool ref-is-glvalue = // exposition only
119
  is_reference_v<range_reference_t<Base>>;
120
 
121
+ OuterIter outer_ = OuterIter(); // exposition only, present only
122
+ // if Base models forward_range
123
+ optional<InnerIter> inner_; // exposition only
124
  Parent* parent_ = nullptr; // exposition only
125
 
126
  constexpr void satisfy(); // exposition only
127
+
128
+ constexpr OuterIter& outer(); // exposition only
129
+ constexpr const OuterIter& outer() const; // exposition only
130
+
131
+ constexpr iterator(Parent& parent, OuterIter outer)
132
+ requires forward_range<Base>; // exposition only
133
+ constexpr explicit iterator(Parent& parent)
134
+ requires (!forward_range<Base>); // exposition only
135
+
136
  public:
137
  using iterator_concept = see below;
138
+ using iterator_category = see below; // not always present
139
  using value_type = range_value_t<range_reference_t<Base>>;
140
  using difference_type = see below;
141
 
142
  iterator() = default;
 
143
  constexpr iterator(iterator<!Const> i)
144
  requires Const &&
145
+ convertible_to<iterator_t<V>, OuterIter> &&
146
+ convertible_to<iterator_t<InnerRng>, InnerIter>;
 
147
 
148
+ constexpr decltype(auto) operator*() const { return **inner_; }
149
 
150
+ constexpr InnerIter operator->() const
151
+ requires has-arrow<InnerIter> && copyable<InnerIter>;
152
 
153
  constexpr iterator& operator++();
154
  constexpr void operator++(int);
155
  constexpr iterator operator++(int)
156
  requires ref-is-glvalue && forward_range<Base> &&
 
165
  requires ref-is-glvalue && bidirectional_range<Base> &&
166
  bidirectional_range<range_reference_t<Base>> &&
167
  common_range<range_reference_t<Base>>;
168
 
169
  friend constexpr bool operator==(const iterator& x, const iterator& y)
170
+ requires ref-is-glvalue && forward_range<Base> &&
171
  equality_comparable<iterator_t<range_reference_t<Base>>>;
172
 
173
  friend constexpr decltype(auto) iter_move(const iterator& i)
174
+ noexcept(noexcept(ranges::iter_move(*i.inner_))) {
175
+ return ranges::iter_move(*i.inner_);
176
  }
177
 
178
  friend constexpr void iter_swap(const iterator& x, const iterator& y)
179
+ noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_)))
180
+ requires indirectly_swappable<InnerIter>;
181
  };
182
  }
183
  ```
184
 
185
  `iterator::iterator_concept` is defined as follows:
186
 
187
+ - If *`ref-is-glvalue`* is `true`, *`Base`* models
188
+ `bidirectional_range`, and `range_reference_t<Base>` models both
189
+ `bidirectional_range` and `common_range`, then `iterator_concept`
190
+ denotes `bidirectional_iterator_tag`.
191
  - Otherwise, if *`ref-is-glvalue`* is `true` and *`Base`* and
192
  `range_reference_t<Base>` each model , then `iterator_concept` denotes
193
  `forward_iterator_tag`.
194
  - Otherwise, `iterator_concept` denotes `input_iterator_tag`.
195
 
196
+ The member *typedef-name* `iterator_category` is defined if and only if
197
+ *`ref-is-glvalue`* is `true`, *`Base`* models `forward_range`, and
198
+ `range_reference_t<Base>` models `forward_range`. In that case,
199
  `iterator::iterator_category` is defined as follows:
200
 
201
  - Let *OUTERC* denote
202
  `iterator_traits<iterator_t<Base>>::iterator_category`, and let
203
  *INNERC* denote
204
  `iterator_traits<iterator_t<range_reference_t<Base>>>::iterator_category`.
205
+ - If *OUTERC* and *INNERC* each model
206
+ `derived_from<bidirectional_iterator_tag>` and
207
+ `range_reference_t<Base>` models `common_range`, `iterator_category`
208
  denotes `bidirectional_iterator_tag`.
 
 
 
209
  - Otherwise, if *OUTERC* and *INNERC* each model
210
+ `derived_from<forward_iterator_tag>`, `iterator_category` denotes
211
+ `forward_iterator_tag`.
212
+ - Otherwise, `iterator_category` denotes `input_iterator_tag`.
213
 
214
  `iterator::difference_type` denotes the type:
215
 
216
  ``` cpp
217
  common_type_t<
 
221
 
222
  `join_view` iterators use the *`satisfy`* function to skip over empty
223
  inner ranges.
224
 
225
  ``` cpp
226
+ constexpr OuterIter& outer();
227
+ constexpr const OuterIter& outer() const;
228
+ ```
229
+
230
+ *Returns:* *outer\_* if *Base* models `forward_range`; otherwise,
231
+ `*`*`parent_`*`->`*`outer_`*.
232
+
233
+ ``` cpp
234
+ constexpr void satisfy();
235
  ```
236
 
237
  *Effects:* Equivalent to:
238
 
239
  ``` cpp
240
+ auto update_inner = [this](const iterator_t<Base>& x) -> auto&& {
241
+ if constexpr (ref-is-glvalue) // *x is a reference
242
+ return *x;
243
  else
244
+ return parent_->inner_.emplace-deref(x);
245
  };
246
 
247
+ for (; outer() != ranges::end(parent_->base_); ++outer()) {
248
+ auto&& inner = update_inner(outer());
249
  inner_ = ranges::begin(inner);
250
+ if (*inner_ != ranges::end(inner))
251
  return;
252
  }
253
  if constexpr (ref-is-glvalue)
254
+ inner_.reset();
255
  ```
256
 
257
  ``` cpp
258
+ constexpr iterator(Parent& parent, OuterIter outer)
259
+ requires forward_range<Base>;
260
  ```
261
 
262
  *Effects:* Initializes *outer\_* with `std::move(outer)` and *parent\_*
263
  with `addressof(parent)`; then calls *`satisfy`*`()`.
264
 
265
+ ``` cpp
266
+ constexpr explicit iterator(Parent& parent)
267
+ requires (!forward_range<Base>);
268
+ ```
269
+
270
+ *Effects:* Initializes *parent\_* with `addressof(parent)`; then calls
271
+ *`satisfy`*`()`.
272
+
273
  ``` cpp
274
  constexpr iterator(iterator<!Const> i)
275
  requires Const &&
276
+ convertible_to<iterator_t<V>, OuterIter> &&
277
+ convertible_to<iterator_t<InnerRng>, InnerIter>;
 
278
  ```
279
 
280
  *Effects:* Initializes *outer\_* with `std::move(i.`*`outer_`*`)`,
281
  *inner\_* with `std::move(i.`*`inner_`*`)`, and *parent\_* with
282
  `i.`*`parent_`*.
283
 
284
+ [*Note 1*: `Const` can only be `true` when *Base* models
285
+ `forward_range`. — *end note*]
286
+
287
  ``` cpp
288
+ constexpr InnerIter operator->() const
289
+ requires has-arrow<InnerIter> && copyable<InnerIter>;
290
  ```
291
 
292
+ *Effects:* Equivalent to: `return *`*`inner_`*`;`
293
 
294
  ``` cpp
295
  constexpr iterator& operator++();
296
  ```
297
 
298
  Let *`inner-range`* be:
299
 
300
+ - If *ref-is-glvalue* is `true`, `*`*`outer`*`()`.
301
+ - Otherwise, `*`*`parent_`*`->`*`inner_`*.
302
 
303
  *Effects:* Equivalent to:
304
 
305
  ``` cpp
306
+ if (++*inner_ == ranges::end(as-lvalue(inner-range))) {
307
+ ++outer();
 
308
  satisfy();
309
  }
310
  return *this;
311
  ```
312
 
 
339
 
340
  *Effects:* Equivalent to:
341
 
342
  ``` cpp
343
  if (outer_ == ranges::end(parent_->base_))
344
+ inner_ = ranges::end(as-lvalue(*--outer_));
345
+ while (*inner_ == ranges::begin(as-lvalue(*outer_)))
346
+ *inner_ = ranges::end(as-lvalue(*--outer_));
347
+ --*inner_;
348
  return *this;
349
  ```
350
 
351
  ``` cpp
352
  constexpr iterator operator--(int)
 
363
  return tmp;
364
  ```
365
 
366
  ``` cpp
367
  friend constexpr bool operator==(const iterator& x, const iterator& y)
368
+ requires ref-is-glvalue && forward_range<Base> &&
369
  equality_comparable<iterator_t<range_reference_t<Base>>>;
370
  ```
371
 
372
  *Effects:* Equivalent to:
373
  `return x.`*`outer_`*` == y.`*`outer_`*` && x.`*`inner_`*` == y.`*`inner_`*`;`
374
 
375
  ``` cpp
376
  friend constexpr void iter_swap(const iterator& x, const iterator& y)
377
+ noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_)))
378
+ requires indirectly_swappable<InnerIter>;
379
  ```
380
 
381
  *Effects:* Equivalent to:
382
+ `return ranges::iter_swap(*x.`*`inner_`*`, *y.`*`inner_`*`);`
383
 
384
  #### Class template `join_view::sentinel` <a id="range.join.sentinel">[[range.join.sentinel]]</a>
385
 
386
  ``` cpp
387
  namespace std::ranges {
388
  template<input_range V>
389
+ requires view<V> && input_range<range_reference_t<V>>
 
 
390
  template<bool Const>
391
  struct join_view<V>::sentinel {
392
  private:
393
+ using Parent = maybe-const<Const, join_view>; // exposition only
394
+ using Base = maybe-const<Const, V>; // exposition only
 
395
  sentinel_t<Base> end_ = sentinel_t<Base>(); // exposition only
396
+
397
  public:
398
  sentinel() = default;
399
 
400
  constexpr explicit sentinel(Parent& parent);
401
  constexpr sentinel(sentinel<!Const> s)
402
  requires Const && convertible_to<sentinel_t<V>, sentinel_t<Base>>;
403
 
404
+ template<bool OtherConst>
405
+ requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
406
+ friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
407
  };
408
  }
409
  ```
410
 
411
  ``` cpp
 
420
  ```
421
 
422
  *Effects:* Initializes *end\_* with `std::move(s.`*`end_`*`)`.
423
 
424
  ``` cpp
425
+ template<bool OtherConst>
426
+ requires sentinel_for<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
427
+ friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
428
  ```
429
 
430
+ *Effects:* Equivalent to: `return x.`*`outer`*`() == y.`*`end_`*`;`
431