From Jason Turner

[range.cartesian]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpnwtrk295/{from.md → to.md} +597 -0
tmp/tmpnwtrk295/{from.md → to.md} RENAMED
@@ -0,0 +1,597 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Cartesian product view <a id="range.cartesian">[[range.cartesian]]</a>
2
+
3
+ #### Overview <a id="range.cartesian.overview">[[range.cartesian.overview]]</a>
4
+
5
+ `cartesian_product_view` takes any non-zero number of ranges n and
6
+ produces a view of tuples calculated by the n-ary cartesian product of
7
+ the provided ranges.
8
+
9
+ The name `views::cartesian_product` denotes a customization point object
10
+ [[customization.point.object]]. Given a pack of subexpressions `Es`, the
11
+ expression `views::cartesian_product(Es...)` is expression-equivalent to
12
+
13
+ - `views::single(tuple())` if `Es` is an empty pack,
14
+ - otherwise,
15
+ `cartesian_product_view<views::all_t<decltype((Es))>...>(Es...)`.
16
+
17
+ [*Example 1*:
18
+
19
+ ``` cpp
20
+ vector<int> v { 0, 1, 2 };
21
+ for (auto&& [a, b, c] : views::cartesian_product(v, v, v)) {
22
+ cout << a << ' ' << b << ' ' << c << '\n';
23
+ }
24
+ // The above prints
25
+ // 0 0 0
26
+ // 0 0 1
27
+ // 0 0 2
28
+ // 0 1 0
29
+ // 0 1 1
30
+ // ...
31
+ ```
32
+
33
+ — *end example*]
34
+
35
+ #### Class template `cartesian_product_view` <a id="range.cartesian.view">[[range.cartesian.view]]</a>
36
+
37
+ ``` cpp
38
+ namespace std::ranges {
39
+ template<bool Const, class First, class... Vs>
40
+ concept cartesian-product-is-random-access = // exposition only
41
+ (random_access_range<maybe-const<Const, First>> && ... &&
42
+ (random_access_range<maybe-const<Const, Vs>>
43
+ && sized_range<maybe-const<Const, Vs>>));
44
+
45
+ template<class R>
46
+ concept cartesian-product-common-arg = // exposition only
47
+ common_range<R> || (sized_range<R> && random_access_range<R>);
48
+
49
+ template<bool Const, class First, class... Vs>
50
+ concept cartesian-product-is-bidirectional = // exposition only
51
+ (bidirectional_range<maybe-const<Const, First>> && ... &&
52
+ (bidirectional_range<maybe-const<Const, Vs>>
53
+ && cartesian-product-common-arg<maybe-const<Const, Vs>>));
54
+
55
+ template<class First, class... Vs>
56
+ concept cartesian-product-is-common = // exposition only
57
+ cartesian-product-common-arg<First>;
58
+
59
+ template<class... Vs>
60
+ concept cartesian-product-is-sized = // exposition only
61
+ (sized_range<Vs> && ...);
62
+
63
+ template<bool Const, template<class> class FirstSent, class First, class... Vs>
64
+ concept cartesian-is-sized-sentinel = // exposition only
65
+ (sized_sentinel_for<FirstSent<maybe-const<Const, First>>,
66
+ iterator_t<maybe-const<Const, First>>> && ...
67
+ && (sized_range<maybe-const<Const, Vs>>
68
+ && sized_sentinel_for<iterator_t<maybe-const<Const, Vs>>,
69
+ iterator_t<maybe-const<Const, Vs>>>));
70
+
71
+ template<cartesian-product-common-arg R>
72
+ constexpr auto cartesian-common-arg-end(R& r) { // exposition only
73
+ if constexpr (common_range<R>) {
74
+ return ranges::end(r);
75
+ } else {
76
+ return ranges::begin(r) + ranges::distance(r);
77
+ }
78
+ }
79
+
80
+ template<input_range First, forward_range... Vs>
81
+ requires (view<First> && ... && view<Vs>)
82
+ class cartesian_product_view : public view_interface<cartesian_product_view<First, Vs...>> {
83
+ private:
84
+ tuple<First, Vs...> bases_; // exposition only
85
+ // [range.cartesian.iterator], class template cartesian_product_view::iterator
86
+ template<bool Const> class iterator; // exposition only
87
+
88
+ public:
89
+ constexpr cartesian_product_view() = default;
90
+ constexpr explicit cartesian_product_view(First first_base, Vs... bases);
91
+
92
+ constexpr iterator<false> begin()
93
+ requires (!simple-view<First> || ... || !simple-view<Vs>);
94
+ constexpr iterator<true> begin() const
95
+ requires (range<const First> && ... && range<const Vs>);
96
+
97
+ constexpr iterator<false> end()
98
+ requires ((!simple-view<First> || ... || !simple-view<Vs>) &&
99
+ cartesian-product-is-common<First, Vs...>);
100
+ constexpr iterator<true> end() const
101
+ requires cartesian-product-is-common<const First, const Vs...>;
102
+ constexpr default_sentinel_t end() const noexcept;
103
+
104
+ constexpr see below size()
105
+ requires cartesian-product-is-sized<First, Vs...>;
106
+ constexpr see below size() const
107
+ requires cartesian-product-is-sized<const First, const Vs...>;
108
+ };
109
+
110
+ template<class... Vs>
111
+ cartesian_product_view(Vs&&...) -> cartesian_product_view<views::all_t<Vs>...>;
112
+ }
113
+ ```
114
+
115
+ ``` cpp
116
+ constexpr explicit cartesian_product_view(First first_base, Vs... bases);
117
+ ```
118
+
119
+ *Effects:* Initializes *bases\_* with
120
+ `std::move(first_base), std::move(bases)...`.
121
+
122
+ ``` cpp
123
+ constexpr iterator<false> begin()
124
+ requires (!simple-view<First> || ... || !simple-view<Vs>);
125
+ ```
126
+
127
+ *Effects:* Equivalent to:
128
+
129
+ ``` cpp
130
+ return iterator<false>(*this, tuple-transform(ranges::begin, bases_));
131
+ ```
132
+
133
+ ``` cpp
134
+ constexpr iterator<true> begin() const
135
+ requires (range<const First> && ... && range<const Vs>);
136
+ ```
137
+
138
+ *Effects:* Equivalent to:
139
+
140
+ ``` cpp
141
+ return iterator<true>(*this, tuple-transform(ranges::begin, bases_));
142
+ ```
143
+
144
+ ``` cpp
145
+ constexpr iterator<false> end()
146
+ requires ((!simple-view<First> || ... || !simple-view<Vs>)
147
+ && cartesian-product-is-common<First, Vs...>);
148
+ constexpr iterator<true> end() const
149
+ requires cartesian-product-is-common<const First, const Vs...>;
150
+ ```
151
+
152
+ Let:
153
+
154
+ - *is-const* be `true` for the const-qualified overload, and `false`
155
+ otherwise;
156
+ - *is-empty* be `true` if the expression `ranges::empty(rng)` is `true`
157
+ for any `rng` among the underlying ranges except the first one and
158
+ `false` otherwise; and
159
+ - *`begin-or-first-end`*`(rng)` be expression-equivalent to
160
+ *`is-empty`*` ? ranges::begin(rng) : `*`cartesian-common-arg-end`*`(rng)`
161
+ if `rng` is the first underlying range and `ranges::begin(rng)`
162
+ otherwise.
163
+
164
+ *Effects:* Equivalent to:
165
+
166
+ ``` cpp
167
+ iterator<is-const> it(*this, tuple-transform(
168
+ [](auto& rng){ return begin-or-first-end(rng); }, bases_));
169
+ return it;
170
+ ```
171
+
172
+ ``` cpp
173
+ constexpr default_sentinel_t end() const noexcept;
174
+ ```
175
+
176
+ *Returns:* `default_sentinel`.
177
+
178
+ ``` cpp
179
+ constexpr see below size()
180
+ requires cartesian-product-is-sized<First, Vs...>;
181
+ constexpr see below size() const
182
+ requires cartesian-product-is-sized<const First, const Vs...>;
183
+ ```
184
+
185
+ The return type is an *implementation-defined* unsigned-integer-like
186
+ type.
187
+
188
+ *Recommended practice:* The return type should be the smallest
189
+ unsigned-integer-like type that is sufficiently wide to store the
190
+ product of the maximum sizes of all the underlying ranges, if such a
191
+ type exists.
192
+
193
+ Let p be the product of the sizes of all the ranges in *bases\_*.
194
+
195
+ *Preconditions:* p can be represented by the return type.
196
+
197
+ *Returns:* p.
198
+
199
+ #### Class template `cartesian_product_view::iterator` <a id="range.cartesian.iterator">[[range.cartesian.iterator]]</a>
200
+
201
+ ``` cpp
202
+ namespace std::ranges {
203
+ template<input_range First, forward_range... Vs>
204
+ requires (view<First> && ... && view<Vs>)
205
+ template<bool Const>
206
+ class cartesian_product_view<First, Vs...>::iterator {
207
+ public:
208
+ using iterator_category = input_iterator_tag;
209
+ using iterator_concept = see below;
210
+ using value_type = tuple<range_value_t<maybe-const<Const, First>>,
211
+ range_value_t<maybe-const<Const, Vs>>...>;
212
+ using reference = tuple<range_reference_t<maybe-const<Const, First>>,
213
+ range_reference_t<maybe-const<Const, Vs>>...>;
214
+ using difference_type = see below;
215
+
216
+ iterator() = default;
217
+
218
+ constexpr iterator(iterator<!Const> i) requires Const &&
219
+ (convertible_to<iterator_t<First>, iterator_t<const First>> &&
220
+ ... && convertible_to<iterator_t<Vs>, iterator_t<const Vs>>);
221
+
222
+ constexpr auto operator*() const;
223
+ constexpr iterator& operator++();
224
+ constexpr void operator++(int);
225
+ constexpr iterator operator++(int) requires forward_range<maybe-const<Const, First>>;
226
+
227
+ constexpr iterator& operator--()
228
+ requires cartesian-product-is-bidirectional<Const, First, Vs...>;
229
+ constexpr iterator operator--(int)
230
+ requires cartesian-product-is-bidirectional<Const, First, Vs...>;
231
+
232
+ constexpr iterator& operator+=(difference_type x)
233
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
234
+ constexpr iterator& operator-=(difference_type x)
235
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
236
+
237
+ constexpr reference operator[](difference_type n) const
238
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
239
+
240
+ friend constexpr bool operator==(const iterator& x, const iterator& y)
241
+ requires equality_comparable<iterator_t<maybe-const<Const, First>>>;
242
+
243
+ friend constexpr bool operator==(const iterator& x, default_sentinel_t);
244
+
245
+ friend constexpr auto operator<=>(const iterator& x, const iterator& y)
246
+ requires all-random-access<Const, First, Vs...>;
247
+
248
+ friend constexpr iterator operator+(const iterator& x, difference_type y)
249
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
250
+ friend constexpr iterator operator+(difference_type x, const iterator& y)
251
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
252
+ friend constexpr iterator operator-(const iterator& x, difference_type y)
253
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
254
+ friend constexpr difference_type operator-(const iterator& x, const iterator& y)
255
+ requires cartesian-is-sized-sentinel<Const, iterator_t, First, Vs...>;
256
+
257
+ friend constexpr difference_type operator-(const iterator& i, default_sentinel_t)
258
+ requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>;
259
+ friend constexpr difference_type operator-(default_sentinel_t, const iterator& i)
260
+ requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>;
261
+
262
+ friend constexpr auto iter_move(const iterator& i) noexcept(see below);
263
+
264
+ friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below)
265
+ requires (indirectly_swappable<iterator_t<maybe-const<Const, First>>> && ... &&
266
+ indirectly_swappable<iterator_t<maybe-const<Const, Vs>>>);
267
+
268
+ private:
269
+ using Parent = maybe-const<Const, cartesian_product_view>; // exposition only
270
+ Parent* parent_ = nullptr; // exposition only
271
+ tuple<iterator_t<maybe-const<Const, First>>,
272
+ iterator_t<maybe-const<Const, Vs>>...> current_; // exposition only
273
+
274
+ template<size_t N = sizeof...(Vs)>
275
+ constexpr void next(); // exposition only
276
+
277
+ template<size_t N = sizeof...(Vs)>
278
+ constexpr void prev(); // exposition only
279
+
280
+ template<class Tuple>
281
+ constexpr difference_type distance-from(const Tuple& t) const; // exposition only
282
+
283
+ constexpr iterator(Parent& parent, tuple<iterator_t<maybe-const<Const, First>>,
284
+ iterator_t<maybe-const<Const, Vs>>...> current); // exposition only
285
+ };
286
+ }
287
+ ```
288
+
289
+ `iterator::iterator_concept` is defined as follows:
290
+
291
+ - If `cartesian-product-is-random-access<Const, First, Vs...>` is
292
+ modeled, then `iterator_concept` denotes `random_access_iterator_tag`.
293
+ - Otherwise, if
294
+ `cartesian-product-is-bidirectional<Const, First, Vs...>` is modeled,
295
+ then `iterator_concept` denotes `bidirectional_iterator_tag`.
296
+ - Otherwise, if `maybe-const<Const, First>` models `forward_range`, then
297
+ `iterator_concept` denotes `forward_iterator_tag`.
298
+ - Otherwise, `iterator_concept` denotes `input_iterator_tag`.
299
+
300
+ `iterator::difference_type` is an *implementation-defined*
301
+ signed-integer-like type.
302
+
303
+ *Recommended practice:* `iterator::difference_type` should be the
304
+ smallest signed-integer-like type that is sufficiently wide to store the
305
+ product of the maximum sizes of all underlying ranges if such a type
306
+ exists.
307
+
308
+ ``` cpp
309
+ template<size_t N = sizeof...(Vs)>
310
+ constexpr void next();
311
+ ```
312
+
313
+ *Effects:* Equivalent to:
314
+
315
+ ``` cpp
316
+ auto& it = std::get<N>(current_);
317
+ ++it;
318
+ if constexpr (N > 0) {
319
+ if (it == ranges::end(std::get<N>(parent_->bases_))) {
320
+ it = ranges::begin(std::get<N>(parent_->bases_));
321
+ next<N - 1>();
322
+ }
323
+ }
324
+ ```
325
+
326
+ ``` cpp
327
+ template<size_t N = sizeof...(Vs)>
328
+ constexpr void prev();
329
+ ```
330
+
331
+ *Effects:* Equivalent to:
332
+
333
+ ``` cpp
334
+ auto& it = std::get<N>(current_);
335
+ if constexpr (N > 0) {
336
+ if (it == ranges::begin(std::get<N>(parent_->bases_))) {
337
+ it = cartesian-common-arg-end(std::get<N>(parent_->bases_));
338
+ prev<N - 1>();
339
+ }
340
+ }
341
+ --it;
342
+ ```
343
+
344
+ ``` cpp
345
+ template<class Tuple>
346
+ constexpr difference_type distance-from(const Tuple& t) const;
347
+ ```
348
+
349
+ Let:
350
+
351
+ - scaled-size(N) be the product of
352
+ `static_cast<difference_type>(ranges::size(std::get<`N`>(`*`parent_`*`->`*`bases_`*`)))`
353
+ and scaled-size(N+1) if N ≤ `sizeof...(Vs)`, otherwise
354
+ `static_cast<difference_type>(1)`;
355
+ - scaled-distance(N) be the product of
356
+ `static_cast<difference_type>(std::get<`N`>(`*`current_`*`) - std::get<`N`>(t))`
357
+ and scaled-size(N+1); and
358
+ - *scaled-sum* be the sum of scaled-distance(N) for every integer
359
+ 0 ≤ N ≤ `sizeof...(Vs)`.
360
+
361
+ *Preconditions:* *scaled-sum* can be represented by `difference_type`.
362
+
363
+ *Returns:* *scaled-sum*.
364
+
365
+ ``` cpp
366
+ constexpr iterator(Parent& parent, tuple<iterator_t<maybe-const<Const, First>>,
367
+ iterator_t<maybe-const<Const, Vs>>...> current);
368
+ ```
369
+
370
+ *Effects:* Initializes *parent\_* with `addressof(parent)` and
371
+ *current\_* with `std::move(current)`.
372
+
373
+ ``` cpp
374
+ constexpr iterator(iterator<!Const> i) requires Const &&
375
+ (convertible_to<iterator_t<First>, iterator_t<const First>> &&
376
+ ... && convertible_to<iterator_t<Vs>, iterator_t<const Vs>>);
377
+ ```
378
+
379
+ *Effects:* Initializes *parent\_* with `i.`*`parent_`* and *current\_*
380
+ with `std::move(i.`*`current_`*`)`.
381
+
382
+ ``` cpp
383
+ constexpr auto operator*() const;
384
+ ```
385
+
386
+ *Effects:* Equivalent to:
387
+
388
+ ``` cpp
389
+ return tuple-transform([](auto& i) -> decltype(auto) { return *i; }, current_);
390
+ ```
391
+
392
+ ``` cpp
393
+ constexpr iterator& operator++();
394
+ ```
395
+
396
+ *Effects:* Equivalent to:
397
+
398
+ ``` cpp
399
+ next();
400
+ return *this;
401
+ ```
402
+
403
+ ``` cpp
404
+ constexpr void operator++(int);
405
+ ```
406
+
407
+ *Effects:* Equivalent to `++*this`.
408
+
409
+ ``` cpp
410
+ constexpr iterator operator++(int) requires forward_range<maybe-const<Const, First>>;
411
+ ```
412
+
413
+ *Effects:* Equivalent to:
414
+
415
+ ``` cpp
416
+ auto tmp = *this;
417
+ ++*this;
418
+ return tmp;
419
+ ```
420
+
421
+ ``` cpp
422
+ constexpr iterator& operator--()
423
+ requires cartesian-product-is-bidirectional<Const, First, Vs...>;
424
+ ```
425
+
426
+ *Effects:* Equivalent to:
427
+
428
+ ``` cpp
429
+ prev();
430
+ return *this;
431
+ ```
432
+
433
+ ``` cpp
434
+ constexpr iterator operator--(int)
435
+ requires cartesian-product-is-bidirectional<Const, First, Vs...>;
436
+ ```
437
+
438
+ *Effects:* Equivalent to:
439
+
440
+ ``` cpp
441
+ auto tmp = *this;
442
+ --*this;
443
+ return tmp;
444
+ ```
445
+
446
+ ``` cpp
447
+ constexpr iterator& operator+=(difference_type x)
448
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
449
+ ```
450
+
451
+ Let `orig` be the value of `*this` before the call.
452
+
453
+ Let `ret` be:
454
+
455
+ - If `x > 0`, the value of `*this` had *next* been called `x` times.
456
+ - Otherwise, if `x < 0`, the value of `*this` had *prev* been called
457
+ `-x` times.
458
+ - Otherwise, `orig`.
459
+
460
+ *Preconditions:* `x` is in the range
461
+ $[\texttt{ranges::distance(*this, ranges::begin(*\textit{parent_}))},$
462
+ $\texttt{ranges::distance(*this, ranges::end(*\textit{parent_}))}]$.
463
+
464
+ *Effects:* Sets the value of `*this` to `ret`.
465
+
466
+ *Returns:* `*this`.
467
+
468
+ *Complexity:* Constant.
469
+
470
+ ``` cpp
471
+ constexpr iterator& operator-=(difference_type x)
472
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
473
+ ```
474
+
475
+ *Effects:* Equivalent to:
476
+
477
+ ``` cpp
478
+ *this += -x;
479
+ return *this;
480
+ ```
481
+
482
+ ``` cpp
483
+ constexpr reference operator[](difference_type n) const
484
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
485
+ ```
486
+
487
+ *Effects:* Equivalent to: `return *((*this) + n);`
488
+
489
+ ``` cpp
490
+ friend constexpr bool operator==(const iterator& x, const iterator& y)
491
+ requires equality_comparable<iterator_t<maybe-const<Const, First>>>;
492
+ ```
493
+
494
+ *Effects:* Equivalent to: `return x.`*`current_`*` == y.`*`current_`*`;`
495
+
496
+ ``` cpp
497
+ friend constexpr bool operator==(const iterator& x, default_sentinel_t);
498
+ ```
499
+
500
+ *Returns:* `true` if
501
+ `std::get<`i`>(x.`*`current_`*`) == ranges::end(std::get<`i`>(x.`*`parent_`*`->`*`bases_`*`))`
502
+ is `true` for any integer 0 ≤ i ≤ `sizeof...(Vs)`; otherwise, `false`.
503
+
504
+ ``` cpp
505
+ friend constexpr auto operator<=>(const iterator& x, const iterator& y)
506
+ requires all-random-access<Const, First, Vs...>;
507
+ ```
508
+
509
+ *Effects:* Equivalent to:
510
+ `return x.`*`current_`*` <=> y.`*`current_`*`;`
511
+
512
+ ``` cpp
513
+ friend constexpr iterator operator+(const iterator& x, difference_type y)
514
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
515
+ ```
516
+
517
+ *Effects:* Equivalent to: `return `*`iterator`*`(x) += y;`
518
+
519
+ ``` cpp
520
+ friend constexpr iterator operator+(difference_type x, const iterator& y)
521
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
522
+ ```
523
+
524
+ *Effects:* Equivalent to: `return y + x;`
525
+
526
+ ``` cpp
527
+ friend constexpr iterator operator-(const iterator& x, difference_type y)
528
+ requires cartesian-product-is-random-access<Const, First, Vs...>;
529
+ ```
530
+
531
+ *Effects:* Equivalent to: `return `*`iterator`*`(x) -= y;`
532
+
533
+ ``` cpp
534
+ friend constexpr difference_type operator-(const iterator& x, const iterator& y)
535
+ requires cartesian-is-sized-sentinel<Const, iterator_t, First, Vs...>;
536
+ ```
537
+
538
+ *Effects:* Equivalent to:
539
+ `return x.`*`distance-from`*`(y.`*`current_`*`);`
540
+
541
+ ``` cpp
542
+ friend constexpr difference_type operator-(const iterator& i, default_sentinel_t)
543
+ requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>;
544
+ ```
545
+
546
+ Let *end-tuple* be an object of a type that is a specialization of
547
+ `tuple`, such that:
548
+
549
+ - `std::get<0>(`*`end-tuple`*`)` has the same value as
550
+ `ranges::end(std::get<0>(i.`*`parent_`*`->`*`bases_`*`))`;
551
+ - `std::get<`N`>(`*`end-tuple`*`)` has the same value as
552
+ `ranges::begin(std::get<`N`>(i.`*`parent_`*`->`*`bases_`*`))` for
553
+ every integer 1 ≤ N ≤ `sizeof...(Vs)`.
554
+
555
+ *Effects:* Equivalent to:
556
+ `return i.`*`distance-from`*`(`*`end-tuple`*`);`
557
+
558
+ ``` cpp
559
+ friend constexpr difference_type operator-(default_sentinel_t s, const iterator& i)
560
+ requires cartesian-is-sized-sentinel<Const, sentinel_t, First, Vs...>;
561
+ ```
562
+
563
+ *Effects:* Equivalent to: `return -(i - s);`
564
+
565
+ ``` cpp
566
+ friend constexpr auto iter_move(const iterator& i) noexcept(see below);
567
+ ```
568
+
569
+ *Effects:* Equivalent to:
570
+ `return `*`tuple-transform`*`(ranges::iter_move, i.`*`current_`*`);`
571
+
572
+ *Remarks:* The exception specification is equivalent to the logical of
573
+ the following expressions:
574
+
575
+ - `noexcept(ranges::iter_move(std::get<`N`>(i.`*`current_`*`)))` for
576
+ every integer 0 ≤ N ≤ `sizeof...(Vs)`,
577
+ - `is_nothrow_move_constructible_v<range_rvalue_reference_t<`*`maybe-const`*`<Const, T>>>`
578
+ for every type `T` in `First, Vs...`.
579
+
580
+ ``` cpp
581
+ friend constexpr void iter_swap(const iterator& l, const iterator& r) noexcept(see below)
582
+ requires (indirectly_swappable<iterator_t<maybe-const<Const, First>>> && ... &&
583
+ indirectly_swappable<iterator_t<maybe-const<Const, Vs>>>);
584
+ ```
585
+
586
+ *Effects:* For every integer 0 ≤ i ≤ `sizeof...(Vs)`, performs:
587
+
588
+ ``` cpp
589
+ ranges::iter_swap(std::get<i>(l.current_), std::get<i>(r.current_))
590
+ ```
591
+
592
+ *Remarks:* The exception specification is equivalent to the logical of
593
+ the following expressions:
594
+
595
+ - `noexcept(ranges::iter_swap(std::get<`i`>(l.`*`current_`*`), std::get<`i`>(r.`*`current_`*`)))`
596
+ for every integer 0 ≤ i ≤ `sizeof...(Vs)`.
597
+