From 01a83883e0a33c5a67b47e7cf072b454106f8f6f Mon Sep 17 00:00:00 2001 From: huixie90 Date: Sat, 23 Sep 2023 21:43:26 +0000 Subject: [PATCH] =?UTF-8?q?Deploying=20to=20gh-pages=20from=20@=20huixie90?= =?UTF-8?q?/cpp=5Fpapers@bee7554be8e30892eed91164a9492a1319ae656a=20?= =?UTF-8?q?=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- concat.lwg.feedback.20230913.md | 6 +- concat.md | 91 +--- generated/concat.html | 913 +++++++++++++++----------------- impl/concat/concat.hpp | 44 +- impl/concat/test/basics.cpp | 21 +- impl/concat/test/issues.cpp | 2 +- 6 files changed, 481 insertions(+), 596 deletions(-) diff --git a/concat.lwg.feedback.20230913.md b/concat.lwg.feedback.20230913.md index ac37940..cb3c685 100644 --- a/concat.lwg.feedback.20230913.md +++ b/concat.lwg.feedback.20230913.md @@ -1,8 +1,8 @@ ``` -[TODO] TK: common-arg is very generic (it is exposition-only); can we give a different name? +[REMOVED] TK: common-arg is very generic (it is exposition-only); can we give a different name? JW: people should think of a better name - we don’t do that now [DONE] JW: maybe_const should be hyphenated -[TODO] TK: [on advance-bwd] we always compute the end but we don’t need to do that for common; in Cartesian product there is something like that; the question is whether we want to do it here, too? +[DONE] TK: [on advance-bwd] we always compute the end but we don’t need to do that for common; in Cartesian product there is something like that; the question is whether we want to do it here, too? JW: anybody want to have that replaced by the tool from Cartesian? JW: implementations can do that anyway TK: equivalent => the + is observable @@ -21,7 +21,7 @@ TK: why would we impose a requirement which isn’t needed TS: you don’t need random access but you can work around that JW: is this an SG9 discussion? That seems to be a design question -[TODO] TK: same discussion: the ranges::end(...) isn’t required to be sized, i.e., we need to use a common range again +[Done] TK: same discussion: the ranges::end(...) isn’t required to be sized, i.e., we need to use a common range again TK: I guess, that is the reason why we shouldn’t bother JG: aside from that point, let’s check if we are happy with the changes TK: it should be back to the prose if we need the end diff --git a/concat.md b/concat.md index 36df244..31408b2 100644 --- a/concat.md +++ b/concat.md @@ -15,7 +15,8 @@ toc: true ## R6 -- Added a section `!common_range && random_access_range && sized_range` +- remove `bidirectional_range` support for `!common_range && random_access_range && sized_range` +- remove `random_access_range` support for `!common_range && random_access_range && sized_range` ## R5 @@ -408,6 +409,8 @@ only concepts and functions can be reused for both of the views, and their defin of `end` function would be very similar, except that `cartesian_product_view` checks the first underlying range and `concat_view` checks the last underlying range. +As per SG9 direction, this section is dropped. + ### `!common_range && (random_accessed_range && sized_range)` In R0 version, `concat_view` is a `common_range` if the last range satisfies @@ -477,6 +480,7 @@ access support in the `concat_view`, they can do auto cv = views::concat(r | views::common, other_views...) ``` +As per LEWG direction, the change proposed in this section is adopted ## Bidirectional Range `concat_view` can model `bidirectional_range` if the underlying ranges satisfy @@ -490,7 +494,7 @@ the following conditions: `--ranges::end(n-1th range)`, assuming n-1th range is not empty, or - `random_access_range && sized_range`, so the position can be reached by `ranges::begin(n-1th range) + (ranges::size(n-1th range) - 1)` in constant - time, assuming n-1th range is not empty. + time, assuming n-1th range is not empty. However, as per LEWG's direction,`!common_range && random_access_range && sized_range` is removed Note that the last underlying range does not have to satisfy this constraint because n-1 can never be the last underlying range. If neither of the two @@ -502,7 +506,7 @@ In the `concat` implementation in [@rangev3], `operator--` is only constrained on all underlying ranges being `bidirectional_range` on the declaration, but its implementation is using `ranges::next(ranges::begin(r), ranges::end(r))` which implicitly requires random access to make the operation constant time. So it -went with the second constraint. In this paper, both are supported. +went with the second constraint. ## Random Access Range @@ -510,7 +514,7 @@ went with the second constraint. In this paper, both are supported. the following conditions: - Every underlying range models `random_access_range` -- All except the last range model `sized_range` +- All except the last range model `common_range` ## Sized Range @@ -667,54 +671,6 @@ namespace std::ranges { } ``` -Add the following to [range.adaptor.helpers]{.sref} - -```diff -namespace std::ranges { -// [...] -+ template -+ concept @*common-arg*@ = // exposition only -+ common_range || (sized_range && random_access_range); -// [...] -} -``` - -Modify the following in [range.cartesian.view]{.sref} - -```diff -namespace std::ranges { -// [...] -- template -- concept @*cartesian-product-common-arg*@ = // exposition only -- common_range || (sized_range && random_access_range); - - template - concept @*cartesian-product-is-bidirectional*@ = // exposition only - (bidirectional_range<@*maybe-const*@> && ... && - (bidirectional_range<@*maybe-const*@> -- && @*cartesian-product-common-arg*@<@*maybe-const*@>)); -+ && @*common-arg*@<@*maybe-const*@>)); - - template - concept @*cartesian-product-is-common*@ = // exposition only -- @*cartesian-product-common-arg*@; -+ @*common-arg*@; - -// [...] - -- template<@*cartesian-product-common-arg*@ R> -+ template<@*common-arg*@ R> - constexpr auto @*cartesian-common-arg-end*@(R& r) { // exposition only - if constexpr (common_range) { - return ranges::end(r); - } else { - return ranges::begin(r) + ranges::distance(r); - } - } -// [...] -} -``` - ## `concat` Add the following subclause to [range.adaptors]{.sref}. @@ -871,7 +827,7 @@ concept @_concat-is-random-access_@ = @*see below*@; // exposition only template concept @_concat-is-random-access_@ = // exposition only @*all-random-access*@ && - (sized_range<@*maybe-const*@> && ...); + (common_range<@*maybe-const*@> && ...); ``` ::: @@ -888,7 +844,7 @@ concept @_concat-is-bidirectional_@ = @*see below*@; // exposition only ```cpp template concept @_concat-is-bidirectional_@ = // exposition only - (@*all-bidirectional*@ && ... && @*common-arg*@<@*maybe-const*@>); + (@*all-bidirectional*@ && ... && common_range<@*maybe-const*@>); ``` ::: @@ -1147,14 +1103,7 @@ if constexpr (N == 0) { --get<0>(@*it_*@); } else { if (get(@*it_*@) == ranges::begin(get(@*parent_*@->@*views_*@))) { - using prev_view = @_maybe-const_@>>; - if constexpr (common_range) { - @*it_*@.template emplace(ranges::end(get(@*parent_*@->@*views_*@))); - } else { - @*it_*@.template emplace( - ranges::next(ranges::begin(get(@*parent_*@->@*views_*@)), - ranges::size(get(@*parent_*@->@*views_*@)))); - } + @*it_*@.template emplace(ranges::end(get(@*parent_*@->@*views_*@))); @_prev_@(); } else { --get(@*it_*@); @@ -1208,7 +1157,7 @@ if constexpr (N == 0) { get(@*it_*@) -= static_cast(steps); } else { auto prev_size = ranges::distance(get(@*parent_*@->@*views_*@)); - @*it_*@.template emplace(ranges::begin(get(@*parent_*@->@*views_*@)) + prev_size); + @*it_*@.template emplace(ranges::end(get(@*parent_*@->@*views_*@))); @*advance-bwd*@(prev_size, steps - offset); } } @@ -1525,17 +1474,17 @@ friend constexpr difference_type operator-(const @_iterator_@& x, const @_iterat denote `y.@*it_*@.index()` - [34.1]{.pnum} if `@*i~x~*@ > @*i~y~*@`, let `@*d~y~*@` be - `ranges::distance(get<@*i~y~*@>(y.@*it_*@), ranges::end(get<@*i~y~*@>(y.@*parent_*@->@*views_*@)))`, + `ranges::distance(get<@*i~y~*@>(y.@*it_*@), ranges::end(get<@*i~y~*@>(y.@*parent_*@->@*views_*@)))`, `@*d~x~*@` be `ranges::distance(ranges::begin(get<@*i~x~*@>(x.@*parent_*@->@*views_*@)), get<@*i~x~*@>(x.@*it_*@))`. Let `s` denote the sum of the sizes of all the ranges `get<@*i*@>(x.@*parent_*@->@*views_*@)` for every integer `@*i~y~*@ < @*i*@ < @*i~x~*@` if there is any, and `0` otherwise, of type - `@*make-unsigned-like-t*@>...>>`, + `difference_type`, equivalent to ```cpp - return @*d~y~*@ + static_cast(s) + @*d~x~*@; + return @*d~y~*@ + s + @*d~x~*@; ``` - [34.2]{.pnum} otherwise, if `@*i~x~*@ < @*i~y~*@`, equivalent to: @@ -1564,19 +1513,19 @@ friend constexpr difference_type operator-(const @_iterator_@& x, default_sentin [36]{.pnum} *Effects*: Let `@*i~x~*@` denote `x.@*it_*@.index()`, `@*d~x~*@` be `ranges::distance(get<@*i~x~*@>(x.@*it_*@), ranges::end(get<@*i~x~*@>(x.@*parent_*@->@*views_*@)))`. Let `s` denote the sum of the sizes of all the ranges -`get<@*i*@>(x.@*parent_*@->@*views_*@)` For every integer +`get<@*i*@>(x.@*parent_*@->@*views_*@)` for every integer `@*i~x~*@ < @*i*@ < sizeof...(Views)` if there is any, and `0` -otherwise, of type `@*make-unsigned-like-t*@>...>>`, +otherwise, of type `difference_type`, equivalent to ```cpp -return -(@*d~x~*@ + static_cast(s)); +return -(@*d~x~*@ + s); ``` [37]{.pnum} *Remarks*: Let `V` be the last element of the pack `Views`, the expression in the requires-clause is equivalent to: ```cpp -(@_concat-is-random-access_@ && sized_range<@*maybe-const*@>) +(@_concat-is-random-access_@ && common_range<@*maybe-const*@>) ``` ::: @@ -1597,7 +1546,7 @@ return -(x - default_sentinel); [39]{.pnum} *Remarks*: Let `V` be the last element of the pack `Views`, the expression in the requires-clause is equivalent to: ```cpp -(@_concat-is-random-access_@ && sized_range<@*maybe-const*@>) +(@_concat-is-random-access_@ && common_range<@*maybe-const*@>) ``` ::: diff --git a/generated/concat.html b/generated/concat.html index 0992cf8..fc8d4c6 100644 --- a/generated/concat.html +++ b/generated/concat.html @@ -495,25 +495,23 @@

Contents

cartesian_product_view
  • 4.5.2 !common_range && (random_accessed_range && sized_range)
  • -
  • 4.6 Bidirectional +
  • 4.6 Random Access Range
  • -
  • 4.7 Random Access -Range
  • -
  • 4.8 Sized Range
  • -
  • 4.9 +
  • 4.7 Sized Range
  • +
  • 4.8 iter_swap Customizations
  • -
  • 4.10 Implementation +
  • 4.9 Implementation Experience
  • 5 Wording @@ -537,7 +535,10 @@

    Contents

    1 Revision History

    1.1 R6

      -
    • Added a section !common_range && random_access_range && sized_range
    • +
    • remove bidirectional_range +support for !common_range && random_access_range && sized_range
    • +
    • remove random_access_range +support for !common_range && random_access_range && sized_range

    1.2 R5

      @@ -1013,6 +1014,7 @@

      the first underlying range and concat_view checks the last underlying range.

      +

      As per SG9 direction, this section is dropped.

      4.5.2 !common_range && (random_accessed_range && sized_range)

      In R0 version, concat_view is a common_range if the last range @@ -1074,7 +1076,8 @@

      concat_view, they can do

      auto cv = views::concat(r | views::common, other_views...)
      -

      4.6 Bidirectional Range

      +

      As per LEWG direction, the change proposed in this section is adopted +## Bidirectional Range

      concat_view can model bidirectional_range if the underlying ranges satisfy the following conditions:

      @@ -1093,7 +1096,9 @@

      random_access_range && sized_range, so the position can be reached by ranges::begin(n-1th range) + (ranges::size(n-1th range) - 1) -in constant time, assuming n-1th range is not empty. +in constant time, assuming n-1th range is not empty. However, as per +LEWG’s direction,!common_range && random_access_range && sized_range +is removed

    Note that the last underlying range does not have to satisfy this constraint because n-1 can never be the last underlying range. If @@ -1110,9 +1115,8 @@

    bidirectional_range on the declaration, but its implementation is using ranges::next(ranges::begin(r), ranges::end(r)) which implicitly requires random access to make the operation constant -time. So it went with the second constraint. In this paper, both are -supported.

    -

    4.7 Random Access Range

    +time. So it went with the second constraint.

    +

    4.6 Random Access Range

    concat_view can model random_access_range if the underlying ranges satisfy the following conditions:

    @@ -1121,16 +1125,16 @@

    random_access_range

  • All except the last range model -sized_range
  • +common_range -

    4.8 Sized Range

    +

    4.7 Sized Range

    concat_view can be sized_range if all the underlying ranges model sized_range

    -

    4.9 +

    4.8 iter_swap Customizations

    -

    4.9.1 Option 1: Delegate to the +

    4.8.1 Option 1: Delegate to the Underlying iter_swap

    This option was originally adopted in the paper. If all the combinations of the underlying iterators model @@ -1171,7 +1175,7 @@

    }

    It turned out that allowing swapping elements across heterogeneous ranges could result in lots of undesired behaviours.

    -

    4.9.2 Option 2: Do not Provide the +

    4.8.2 Option 2: Do not Provide the Customization

    If the iter_swap customization is removed, the above examples are no longer an issue @@ -1189,7 +1193,7 @@

    concat the same type of ranges with iter_swap customizations.

    -

    4.9.3 Option 3: Delegate to the +

    4.8.3 Option 3: Delegate to the Underlying iter_swap Only If They Have the Same Type

    This option was suggested by Tomasz in the SG9 mailing list. The idea @@ -1211,7 +1215,7 @@

    4.10 Implementation Experience

    +

    4.9 Implementation Experience

    views::concat has been implemented in [range-v3], with equivalent semantics as proposed here. The authors also implemented a @@ -1280,52 +1284,6 @@

    // [...] } -

    Add the following to 26.7.5 -[range.adaptor.helpers]

    -
    -
    namespace std::ranges {
    -// [...]
    -+ template<class R>
    -+   concept common-arg =                        // exposition only
    -+     common_range<R> || (sized_range<R> && random_access_range<R>);
    -// [...]
    -}
    -
    -

    Modify the following in 26.7.32.2 -[range.cartesian.view]

    -
    -
    namespace std::ranges {
    -// [...]
    -- template<class R>
    --   concept cartesian-product-common-arg =      // exposition only
    --     common_range<R> || (sized_range<R> && random_access_range<R>);
    -
    -  template<bool Const, class First, class... Vs>
    -  concept cartesian-product-is-bidirectional =          // exposition only
    -    (bidirectional_range<maybe-const<Const, First>> && ... &&
    -      (bidirectional_range<maybe-const<Const, Vs>>
    --        && cartesian-product-common-arg<maybe-const<Const, Vs>>));
    -+        && common-arg<maybe-const<Const, Vs>>));
    -
    -  template<class First, class... Vs>
    -  concept cartesian-product-is-common =                 // exposition only
    --    cartesian-product-common-arg<First>;
    -+    common-arg<First>;
    -
    -// [...]
    -
    --  template<cartesian-product-common-arg R>
    -+  template<common-arg R>
    -  constexpr auto cartesian-common-arg-end(R& r) {       // exposition only
    -    if constexpr (common_range<R>) {
    -      return ranges::end(r);
    -    } else {
    -      return ranges::begin(r) + ranges::distance(r);
    -    }
    -  }
    -// [...]
    -}
    -

    5.3 concat

    Add the following subclause to 26.7 @@ -1357,115 +1315,115 @@

    ?.?.?.1 concat_view(Es...)

    [Example:

    -
    std::vector<int> v1{1,2,3}, v2{4,5}, v3{};
    -std::array  a{6,7,8};
    -auto s = std::views::single(9);
    -for(auto&& i : std::views::concat(v1, v2, v3, a, s)){
    -  std::cout << i << ' '; // prints: 1 2 3 4 5 6 7 8 9 
    -}
    +
    std::vector<int> v1{1,2,3}, v2{4,5}, v3{};
    +std::array  a{6,7,8};
    +auto s = std::views::single(9);
    +for(auto&& i : std::views::concat(v1, v2, v3, a, s)){
    +  std::cout << i << ' '; // prints: 1 2 3 4 5 6 7 8 9 
    +}
    • end example]

    ?.?.?.2 Class template concat_view [range.concat.view]

    -
    namespace std::ranges {
    -
    -  template <class... Rs>
    -  using concat-reference-t = common_reference_t<range_reference_t<Rs>...>; // exposition only
    -
    -  template <class... Rs>
    -  using concat-value-t = common_type_t<range_value_t<Rs>...>; // exposition only
    -
    -  template <class... Rs>
    -  using concat-rvalue-reference-t = common_reference_t<range_rvalue_reference_t<Rs>...>; // exposition only
    -
    -  template <class... Rs>
    -  concept concat-indirectly-readable = see below; // exposition only
    -
    -  template <class... Rs>
    -  concept concatable = see below;             // exposition only
    -
    -  template <bool Const, class... Rs>
    -  concept concat-is-random-access = see below;   // exposition only
    -
    -  template <bool Const, class... Rs>
    -  concept concat-is-bidirectional = see below;   // exposition only
    -
    -  template <input_range... Views>
    -    requires (view<Views> && ...) && (sizeof...(Views) > 0) &&
    -              concatable<Views...>
    -  class concat_view : public view_interface<concat_view<Views...>> {
    -    tuple<Views...> views_;                   // exposition only
    -
    -    template <bool Const>
    -    class iterator;                           // exposition only
    -
    -  public:
    -    constexpr concat_view() = default;
    -
    -    constexpr explicit concat_view(Views... views);
    -
    -    constexpr iterator<false> begin() requires(!(simple-view<Views> && ...));
    -
    -    constexpr iterator<true> begin() const
    -      requires((range<const Views> && ...) && concatable<const Views...>);
    -
    -    constexpr auto end() requires(!(simple-view<Views> && ...));
    -
    -    constexpr auto end() const requires(range<const Views>&&...);
    -
    -    constexpr auto size() requires(sized_range<Views>&&...);
    -
    -    constexpr auto size() const requires(sized_range<const Views>&&...);
    -  };
    -
    -  template <class... R>
    -    concat_view(R&&...) -> concat_view<views::all_t<R>...>;
    -}
    -
    template <class... Rs>
    -concept concat-indirectly-readable = see below; // exposition only
    +
    namespace std::ranges {
    +
    +  template <class... Rs>
    +  using concat-reference-t = common_reference_t<range_reference_t<Rs>...>; // exposition only
    +
    +  template <class... Rs>
    +  using concat-value-t = common_type_t<range_value_t<Rs>...>; // exposition only
    +
    +  template <class... Rs>
    +  using concat-rvalue-reference-t = common_reference_t<range_rvalue_reference_t<Rs>...>; // exposition only
    +
    +  template <class... Rs>
    +  concept concat-indirectly-readable = see below; // exposition only
    +
    +  template <class... Rs>
    +  concept concatable = see below;             // exposition only
    +
    +  template <bool Const, class... Rs>
    +  concept concat-is-random-access = see below;   // exposition only
    +
    +  template <bool Const, class... Rs>
    +  concept concat-is-bidirectional = see below;   // exposition only
    +
    +  template <input_range... Views>
    +    requires (view<Views> && ...) && (sizeof...(Views) > 0) &&
    +              concatable<Views...>
    +  class concat_view : public view_interface<concat_view<Views...>> {
    +    tuple<Views...> views_;                   // exposition only
    +
    +    template <bool Const>
    +    class iterator;                           // exposition only
    +
    +  public:
    +    constexpr concat_view() = default;
    +
    +    constexpr explicit concat_view(Views... views);
    +
    +    constexpr iterator<false> begin() requires(!(simple-view<Views> && ...));
    +
    +    constexpr iterator<true> begin() const
    +      requires((range<const Views> && ...) && concatable<const Views...>);
    +
    +    constexpr auto end() requires(!(simple-view<Views> && ...));
    +
    +    constexpr auto end() const requires(range<const Views>&&...);
    +
    +    constexpr auto size() requires(sized_range<Views>&&...);
    +
    +    constexpr auto size() const requires(sized_range<const Views>&&...);
    +  };
    +
    +  template <class... R>
    +    concat_view(R&&...) -> concat_view<views::all_t<R>...>;
    +}
    +
    template <class... Rs>
    +concept concat-indirectly-readable = see below; // exposition only

    1 The exposition-only concat-indirectly-readable concept is equivalent to:

    -
    template <class Ref, class RRef, class It>
    -concept concat-indirectly-readable-impl =  // exposition only
    -requires (const It it) { 
    -  { *it } -> convertible_to<Ref>;
    -  { ranges::iter_move(it) } -> convertible_to<RRef>;
    -};
    -
    -template <class... Rs>
    -concept concat-indirectly-readable = // exposition only
    -  common_reference_with<concat-reference-t<Rs...>&&, 
    -                        concat-value-t<Rs...>&> &&
    -  common_reference_with<concat-reference-t<Rs...>&&, 
    -                        concat-rvalue-reference-t<Rs...>&&> &&
    -  common_reference_with<concat-rvalue-reference-t<Rs...>&&, 
    -                        concat-value-t<Rs...> const&> &&
    -  (concat-indirectly-readable-impl<concat-reference-t<Rs...>, 
    -                                   concat-rvalue-reference-t<Rs...>, 
    -                                   iterator_t<Rs>> && ...);
    +
    template <class Ref, class RRef, class It>
    +concept concat-indirectly-readable-impl =  // exposition only
    +requires (const It it) { 
    +  { *it } -> convertible_to<Ref>;
    +  { ranges::iter_move(it) } -> convertible_to<RRef>;
    +};
    +
    +template <class... Rs>
    +concept concat-indirectly-readable = // exposition only
    +  common_reference_with<concat-reference-t<Rs...>&&, 
    +                        concat-value-t<Rs...>&> &&
    +  common_reference_with<concat-reference-t<Rs...>&&, 
    +                        concat-rvalue-reference-t<Rs...>&&> &&
    +  common_reference_with<concat-rvalue-reference-t<Rs...>&&, 
    +                        concat-value-t<Rs...> const&> &&
    +  (concat-indirectly-readable-impl<concat-reference-t<Rs...>, 
    +                                   concat-rvalue-reference-t<Rs...>, 
    +                                   iterator_t<Rs>> && ...);
    -
    template <class... Rs>
    -concept concatable = see below; // exposition only
    +
    template <class... Rs>
    +concept concatable = see below; // exposition only

    2 The exposition-only concatable concept is equivalent to:

    -
    template <class... Rs>
    -concept concatable = requires { // exposition only
    -  typename concat-reference-t<Rs...>;
    -  typename concat-value-t<Rs...>;
    -  typename concat-rvalue-reference-t<Rs...>;
    -} && concat-indirectly-readable<Rs...>;
    +
    template <class... Rs>
    +concept concatable = requires { // exposition only
    +  typename concat-reference-t<Rs...>;
    +  typename concat-value-t<Rs...>;
    +  typename concat-rvalue-reference-t<Rs...>;
    +} && concat-indirectly-readable<Rs...>;
    -
    template <bool Const, class... Rs>
    -concept concat-is-random-access = see below; // exposition only
    +
    template <bool Const, class... Rs>
    +concept concat-is-random-access = see below; // exposition only

    3 Let Fs be the pack that consists @@ -1473,13 +1431,13 @@

    ?.?.?.2 last, then concat-is-random-access is equivalent to:

    -
    template <bool Const, class... Rs>
    -concept concat-is-random-access = // exposition only
    -   all-random-access<Const, Rs...> &&
    -   (sized_range<maybe-const<Const, Fs>> && ...);
    +
    template <bool Const, class... Rs>
    +concept concat-is-random-access = // exposition only
    +   all-random-access<Const, Rs...> &&
    +   (common_range<maybe-const<Const, Fs>> && ...);

    -
    template <bool Const, class... Rs>
    -concept concat-is-bidirectional = see below; // exposition only
    +
    template <bool Const, class... Rs>
    +concept concat-is-bidirectional = see below; // exposition only

    4 Let Fs be the pack that consists @@ -1487,20 +1445,20 @@

    ?.?.?.2 last element, then concat-is-bidirectional is equivalent to:

    -
    template <bool Const, class... Rs>
    -concept concat-is-bidirectional = // exposition only
    -  (all-bidirectional<Const, Rs...> && ... && common-arg<maybe-const<Const, Fs>>);
    +
    template <bool Const, class... Rs>
    +concept concat-is-bidirectional = // exposition only
    +  (all-bidirectional<Const, Rs...> && ... && common_range<maybe-const<Const, Fs>>);

    -
    constexpr explicit concat_view(Views... views);
    +
    constexpr explicit concat_view(Views... views);

    5 Effects: Initializes views_ with std::move(views)....

    -
    constexpr iterator<false> begin() requires(!(simple-view<Views> && ...));
    -constexpr iterator<true> begin() const
    -  requires((range<const Views> && ...) && concatable<const Views...>);
    +
    constexpr iterator<false> begin() requires(!(simple-view<Views> && ...));
    +constexpr iterator<true> begin() const
    +  requires((range<const Views> && ...) && concatable<const Views...>);

    6 Effects: Let @@ -1508,12 +1466,12 @@

    ?.?.?.2 true for the const-qualified overload, and false otherwise. Equivalent to:

    -
    iterator<is-const> it(this, in_place_index<0>, ranges::begin(get<0>(views_)));
    -it.template satisfy<0>();
    -return it;
    +
    iterator<is-const> it(this, in_place_index<0>, ranges::begin(get<0>(views_)));
    +it.template satisfy<0>();
    +return it;

    -
    constexpr auto end() requires(!(simple-view<Views> && ...));
    -constexpr auto end() const requires(range<const Views>&&...);
    +
    constexpr auto end() requires(!(simple-view<Views> && ...));
    +constexpr auto end() const requires(range<const Views>&&...);

    7 Effects: Let @@ -1526,142 +1484,142 @@

    ?.?.?.2 const-qualified overload, and the last element of the pack Views... otherwise. Equivalent to:

    -
    if constexpr (common_range<last-view>) {
    -    constexpr auto N = sizeof...(Views);
    -    return iterator<is-const>(this, in_place_index<N - 1>, 
    -                      ranges::end(get<N - 1>(views_)));
    -} else {
    -    return default_sentinel;
    -}
    +
    if constexpr (common_range<last-view>) {
    +    constexpr auto N = sizeof...(Views);
    +    return iterator<is-const>(this, in_place_index<N - 1>, 
    +                      ranges::end(get<N - 1>(views_)));
    +} else {
    +    return default_sentinel;
    +}

    -
    constexpr auto size() requires(sized_range<Views>&&...);
    -constexpr auto size() const requires(sized_range<const Views>&&...);
    +
    constexpr auto size() requires(sized_range<Views>&&...);
    +constexpr auto size() const requires(sized_range<const Views>&&...);

    8 Effects: Equivalent to:

    -
    return apply(
    -    [](auto... sizes) {
    -        using CT = make-unsigned-like-t<common_type_t<decltype(sizes)...>>;
    -        return (CT(sizes) + ...);
    -    },
    -    tuple-transform(ranges::size, views_));
    +
    return apply(
    +    [](auto... sizes) {
    +        using CT = make-unsigned-like-t<common_type_t<decltype(sizes)...>>;
    +        return (CT(sizes) + ...);
    +    },
    +    tuple-transform(ranges::size, views_));

    ?.?.?.3 Class concat_view::iterator [range.concat.iterator]

    -
    namespace std::ranges{
    -
    -  template <input_range... Views>
    -    requires (view<Views> && ...) && (sizeof...(Views) > 0) &&
    -              concatable<Views...>
    -  template <bool Const>
    -  class concat_view<Views...>::iterator {
    -  
    -  public:
    -    using iterator_category = see below;                  // not always present.
    -    using iterator_concept = see below;
    -    using value_type = concat-value-t<maybe-const<Const, Views>...>;
    -    using difference_type = common_type_t<range_difference_t<maybe-const<Const, Views>>...>;
    -
    -  private:
    -    using base-iter =                                     // exposition only
    -      variant<iterator_t<maybe-const<Const, Views>>...>;
    -    
    -    maybe-const<Const, concat_view>* parent_ = nullptr;   // exposition only
    -    base-iter it_;                                        // exposition only
    -
    -    template <std::size_t N>
    -    constexpr void satisfy();                             // exposition only
    -
    -    template <std::size_t N>
    -    constexpr void prev();                                // exposition only
    -
    -    template <std::size_t N>
    -    constexpr void advance-fwd(difference_type offset, difference_type steps); // exposition only
    -
    -    template <std::size_t N>
    -    constexpr void advance-bwd(difference_type offset, difference_type steps); // exposition only
    -
    -    template <class... Args>
    -    explicit constexpr iterator(maybe-const<Const, concat_view>* parent, Args&&... args) 
    -        requires constructible_from<base-iter, Args&&...>;  // exposition only
    -
    -  public:
    -
    -    iterator() = default;
    -
    -    constexpr iterator(iterator<!Const> i) 
    -        requires Const && (convertible_to<iterator_t<Views>, iterator_t<const Views>> && ...);
    -
    -    constexpr decltype(auto) operator*() const;
    -
    -    constexpr iterator& operator++();
    -
    -    constexpr void operator++(int);
    -
    -    constexpr iterator operator++(int) 
    -        requires all-forward<Const, Views...>;
    -    
    -    constexpr iterator& operator--() 
    -        requires concat-is-bidirectional<Const, Views...>;
    -
    -    constexpr iterator operator--(int) 
    -        requires concat-is-bidirectional<Const, Views...>;
    -
    -    constexpr iterator& operator+=(difference_type n) 
    -        requires concat-is-random-access<Const, Views...>;
    -
    -    constexpr iterator& operator-=(difference_type n) 
    -        requires concat-is-random-access<Const, Views...>;
    -
    -    constexpr decltype(auto) operator[](difference_type n) const
    -        requires concat-is-random-access<Const, Views...>;
    -
    -    friend constexpr bool operator==(const iterator& x, const iterator& y)
    -        requires(equality_comparable<iterator_t<maybe-const<Const, Views>>>&&...);
    -
    -    friend constexpr bool operator==(const iterator& it, default_sentinel_t);
    -
    -    friend constexpr bool operator<(const iterator& x, const iterator& y)
    -        requires all-random-access<Const, Views...>;
    -
    -    friend constexpr bool operator>(const iterator& x, const iterator& y)
    -        requires all-random-access<Const, Views...>;
    -
    -    friend constexpr bool operator<=(const iterator& x, const iterator& y)
    -        requires all-random-access<Const, Views...>;
    -
    -    friend constexpr bool operator>=(const iterator& x, const iterator& y)
    -        requires all-random-access<Const, Views...>;
    -
    -    friend constexpr auto operator<=>(const iterator& x, const iterator& y)
    -        requires (all-random-access<Const, Views...> &&
    -         (three_way_comparable<maybe-const<Const, Views>> &&...));
    -
    -    friend constexpr iterator operator+(const iterator& it, difference_type n)
    -        requires concat-is-random-access<Const, Views...>;
    -
    -    friend constexpr iterator operator+(difference_type n, const iterator& it)
    -        requires concat-is-random-access<Const, Views...>;
    -
    -    friend constexpr iterator operator-(const iterator& it, difference_type n)
    -        requires concat-is-random-access<Const, Views...>;
    -
    -    friend constexpr difference_type operator-(const iterator& x, const iterator& y) 
    -        requires concat-is-random-access<Const, Views...>;
    -
    -    friend constexpr difference_type operator-(const iterator& x, default_sentinel_t) 
    -        requires see below;
    -
    -    friend constexpr difference_type operator-(default_sentinel_t, const iterator& x) 
    -        requires see below;
    -
    -    friend constexpr decltype(auto) iter_move(const iterator& it) noexcept(see below);
    -
    -    friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below)
    -        requires see below;
    -  };
    -
    -}
    +
    namespace std::ranges{
    +
    +  template <input_range... Views>
    +    requires (view<Views> && ...) && (sizeof...(Views) > 0) &&
    +              concatable<Views...>
    +  template <bool Const>
    +  class concat_view<Views...>::iterator {
    +  
    +  public:
    +    using iterator_category = see below;                  // not always present.
    +    using iterator_concept = see below;
    +    using value_type = concat-value-t<maybe-const<Const, Views>...>;
    +    using difference_type = common_type_t<range_difference_t<maybe-const<Const, Views>>...>;
    +
    +  private:
    +    using base-iter =                                     // exposition only
    +      variant<iterator_t<maybe-const<Const, Views>>...>;
    +    
    +    maybe-const<Const, concat_view>* parent_ = nullptr;   // exposition only
    +    base-iter it_;                                        // exposition only
    +
    +    template <std::size_t N>
    +    constexpr void satisfy();                             // exposition only
    +
    +    template <std::size_t N>
    +    constexpr void prev();                                // exposition only
    +
    +    template <std::size_t N>
    +    constexpr void advance-fwd(difference_type offset, difference_type steps); // exposition only
    +
    +    template <std::size_t N>
    +    constexpr void advance-bwd(difference_type offset, difference_type steps); // exposition only
    +
    +    template <class... Args>
    +    explicit constexpr iterator(maybe-const<Const, concat_view>* parent, Args&&... args) 
    +        requires constructible_from<base-iter, Args&&...>;  // exposition only
    +
    +  public:
    +
    +    iterator() = default;
    +
    +    constexpr iterator(iterator<!Const> i) 
    +        requires Const && (convertible_to<iterator_t<Views>, iterator_t<const Views>> && ...);
    +
    +    constexpr decltype(auto) operator*() const;
    +
    +    constexpr iterator& operator++();
    +
    +    constexpr void operator++(int);
    +
    +    constexpr iterator operator++(int) 
    +        requires all-forward<Const, Views...>;
    +    
    +    constexpr iterator& operator--() 
    +        requires concat-is-bidirectional<Const, Views...>;
    +
    +    constexpr iterator operator--(int) 
    +        requires concat-is-bidirectional<Const, Views...>;
    +
    +    constexpr iterator& operator+=(difference_type n) 
    +        requires concat-is-random-access<Const, Views...>;
    +
    +    constexpr iterator& operator-=(difference_type n) 
    +        requires concat-is-random-access<Const, Views...>;
    +
    +    constexpr decltype(auto) operator[](difference_type n) const
    +        requires concat-is-random-access<Const, Views...>;
    +
    +    friend constexpr bool operator==(const iterator& x, const iterator& y)
    +        requires(equality_comparable<iterator_t<maybe-const<Const, Views>>>&&...);
    +
    +    friend constexpr bool operator==(const iterator& it, default_sentinel_t);
    +
    +    friend constexpr bool operator<(const iterator& x, const iterator& y)
    +        requires all-random-access<Const, Views...>;
    +
    +    friend constexpr bool operator>(const iterator& x, const iterator& y)
    +        requires all-random-access<Const, Views...>;
    +
    +    friend constexpr bool operator<=(const iterator& x, const iterator& y)
    +        requires all-random-access<Const, Views...>;
    +
    +    friend constexpr bool operator>=(const iterator& x, const iterator& y)
    +        requires all-random-access<Const, Views...>;
    +
    +    friend constexpr auto operator<=>(const iterator& x, const iterator& y)
    +        requires (all-random-access<Const, Views...> &&
    +         (three_way_comparable<maybe-const<Const, Views>> &&...));
    +
    +    friend constexpr iterator operator+(const iterator& it, difference_type n)
    +        requires concat-is-random-access<Const, Views...>;
    +
    +    friend constexpr iterator operator+(difference_type n, const iterator& it)
    +        requires concat-is-random-access<Const, Views...>;
    +
    +    friend constexpr iterator operator-(const iterator& it, difference_type n)
    +        requires concat-is-random-access<Const, Views...>;
    +
    +    friend constexpr difference_type operator-(const iterator& x, const iterator& y) 
    +        requires concat-is-random-access<Const, Views...>;
    +
    +    friend constexpr difference_type operator-(const iterator& x, default_sentinel_t) 
    +        requires see below;
    +
    +    friend constexpr difference_type operator-(default_sentinel_t, const iterator& x) 
    +        requires see below;
    +
    +    friend constexpr decltype(auto) iter_move(const iterator& it) noexcept(see below);
    +
    +    friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below)
    +        requires see below;
    +  };
    +
    +}

    1 iterator::iterator_concept is defined as follows:

    @@ -1722,82 +1680,75 @@

    ?.?. denotes input_iterator_tag. -
    template <std::size_t N>
    -constexpr void satisfy();                             // exposition only
    +
    template <std::size_t N>
    +constexpr void satisfy();                             // exposition only

    3 Effects: Equivalent to:

    -
    if constexpr (N < (sizeof...(Views) - 1)) {
    -    if (get<N>(it_) == ranges::end(get<N>(parent_->views_))) {
    -        it_.template emplace<N + 1>(ranges::begin(get<N + 1>(parent_->views_)));
    -        satisfy<N + 1>();
    -    }
    -}
    +
    if constexpr (N < (sizeof...(Views) - 1)) {
    +    if (get<N>(it_) == ranges::end(get<N>(parent_->views_))) {
    +        it_.template emplace<N + 1>(ranges::begin(get<N + 1>(parent_->views_)));
    +        satisfy<N + 1>();
    +    }
    +}
    -
    template <std::size_t N>
    -constexpr void prev();                                // exposition only
    +
    template <std::size_t N>
    +constexpr void prev();                                // exposition only

    4 Effects: Equivalent to:

    -
    if constexpr (N == 0) {
    -    --get<0>(it_);
    -} else {
    -    if (get<N>(it_) == ranges::begin(get<N>(parent_->views_))) {
    -        using prev_view = maybe-const<Const, tuple_element_t<N - 1, tuple<Views...>>>;
    -        if constexpr (common_range<prev_view>) {
    -            it_.template emplace<N - 1>(ranges::end(get<N - 1>(parent_->views_)));
    -        } else {
    -            it_.template emplace<N - 1>(
    -                ranges::next(ranges::begin(get<N - 1>(parent_->views_)),
    -                             ranges::size(get<N - 1>(parent_->views_))));
    -        }
    -        prev<N - 1>();
    -    } else {
    -        --get<N>(it_);
    -    }
    -}
    +
    if constexpr (N == 0) {
    +    --get<0>(it_);
    +} else {
    +    if (get<N>(it_) == ranges::begin(get<N>(parent_->views_))) {
    +        it_.template emplace<N - 1>(ranges::end(get<N - 1>(parent_->views_)));
    +        prev<N - 1>();
    +    } else {
    +        --get<N>(it_);
    +    }
    +}
    -
    template <std::size_t N>
    -constexpr void advance-fwd(difference_type offset, difference_type steps); // exposition only
    +
    template <std::size_t N>
    +constexpr void advance-fwd(difference_type offset, difference_type steps); // exposition only

    5 Effects: Equivalent to:

    -
    using underlying_diff_type = iter_difference_t<variant_alternative_t<N, base-iter>>;
    -if constexpr (N == sizeof...(Views) - 1) {
    -    get<N>(it_) += static_cast<underlying_diff_type>(steps);
    -} else {
    -    auto n_size = ranges::distance(get<N>(parent_->views_));
    -    if (offset + steps < n_size) {
    -        get<N>(it_) += static_cast<underlying_diff_type>(steps);
    -    } else {
    -        it_.template emplace<N + 1>(ranges::begin(get<N + 1>(parent_->views_)));
    -        advance-fwd<N + 1>(0, offset + steps - n_size);
    -    }
    -}
    +
    using underlying_diff_type = iter_difference_t<variant_alternative_t<N, base-iter>>;
    +if constexpr (N == sizeof...(Views) - 1) {
    +    get<N>(it_) += static_cast<underlying_diff_type>(steps);
    +} else {
    +    auto n_size = ranges::distance(get<N>(parent_->views_));
    +    if (offset + steps < n_size) {
    +        get<N>(it_) += static_cast<underlying_diff_type>(steps);
    +    } else {
    +        it_.template emplace<N + 1>(ranges::begin(get<N + 1>(parent_->views_)));
    +        advance-fwd<N + 1>(0, offset + steps - n_size);
    +    }
    +}
    -
    template <std::size_t N>
    -constexpr void advance-bwd(difference_type offset, difference_type steps); // exposition only
    +
    template <std::size_t N>
    +constexpr void advance-bwd(difference_type offset, difference_type steps); // exposition only

    6 Effects: Equivalent to:

    -
    using underlying_diff_type = iter_difference_t<variant_alternative_t<N, base-iter>>;
    -if constexpr (N == 0) {
    -    get<N>(it_) -= static_cast<underlying_diff_type>(steps);
    -} else {
    -    if (offset >= steps) {
    -        get<N>(it_) -= static_cast<underlying_diff_type>(steps);
    -    } else {
    -        auto prev_size = ranges::distance(get<N - 1>(parent_->views_));
    -        it_.template emplace<N - 1>(ranges::begin(get<N - 1>(parent_->views_)) + prev_size);
    -        advance-bwd<N - 1>(prev_size, steps - offset);
    -    }
    -}
    +
    using underlying_diff_type = iter_difference_t<variant_alternative_t<N, base-iter>>;
    +if constexpr (N == 0) {
    +    get<N>(it_) -= static_cast<underlying_diff_type>(steps);
    +} else {
    +    if (offset >= steps) {
    +        get<N>(it_) -= static_cast<underlying_diff_type>(steps);
    +    } else {
    +        auto prev_size = ranges::distance(get<N - 1>(parent_->views_));
    +        it_.template emplace<N - 1>(ranges::end(get<N - 1>(parent_->views_)));
    +        advance-bwd<N - 1>(prev_size, steps - offset);
    +    }
    +}
    -
    template <class... Args>
    -explicit constexpr iterator(
    -            maybe-const<Const, concat_view>* parent,
    -            Args&&... args) 
    -    requires constructible_from<base-iter, Args&&...>; // exposition only
    +
    template <class... Args>
    +explicit constexpr iterator(
    +            maybe-const<Const, concat_view>* parent,
    +            Args&&... args) 
    +    requires constructible_from<base-iter, Args&&...>; // exposition only

    7 Effects: Initializes @@ -1805,9 +1756,9 @@

    ?.?. parent, and initializes it_ with std::forward<Args>(args)....

    -
    constexpr iterator(iterator<!Const> i) 
    -    requires Const &&
    -    (convertible_to<iterator_t<Views>, iterator_t<const Views>>&&...);
    +
    constexpr iterator(iterator<!Const> i) 
    +    requires Const &&
    +    (convertible_to<iterator_t<Views>, iterator_t<const Views>>&&...);

    8 Effects: Initializes @@ -1816,7 +1767,7 @@

    ?.?. initializes it_ with std::move(i.it_).

    -
    constexpr decltype(auto) operator*() const;
    +
    constexpr decltype(auto) operator*() const;

    9 Preconditions: @@ -1824,11 +1775,11 @@

    ?.?. is false.

    10 Effects: Equivalent to:

    -
    using reference = concat-reference-t<maybe-const<Const, Views>...>;
    -return std::visit([](auto&& it) -> reference { 
    -    return *it; }, it_);
    +
    using reference = concat-reference-t<maybe-const<Const, Views>...>;
    +return std::visit([](auto&& it) -> reference { 
    +    return *it; }, it_);

    -
    constexpr iterator& operator++();
    +
    constexpr iterator& operator++();

    11 Preconditions: @@ -1838,27 +1789,27 @@

    ?.?. Effects: Let i be it_.index(). Equivalent to:

    -
    ++get<i>(it_);
    -satisfy<i>();
    -return *this;
    +
    ++get<i>(it_);
    +satisfy<i>();
    +return *this;

    -
    constexpr void operator++(int);
    +
    constexpr void operator++(int);

    13 Effects: Equivalent to:

    -
    ++*this;
    +
    ++*this;
    -
    constexpr iterator operator++(int) 
    -    requires all-forward<Const, Views...>;
    +
    constexpr iterator operator++(int) 
    +    requires all-forward<Const, Views...>;

    14 Effects: Equivalent to:

    -
    auto tmp = *this;
    -++*this;
    -return tmp;
    +
    auto tmp = *this;
    +++*this;
    +return tmp;
    -
    constexpr iterator& operator--() 
    -    requires concat-is-bidirectional<Const, Views...>;
    +
    constexpr iterator& operator--() 
    +    requires concat-is-bidirectional<Const, Views...>;

    15 Preconditions: @@ -1868,20 +1819,20 @@

    ?.?. Effects: Let i be it_.index(). Equivalent to:

    -
    prev<i>();
    -return *this;
    +
    prev<i>();
    +return *this;

    -
    constexpr iterator operator--(int) 
    -    requires concat-is-bidirectional<Const, Views...>;
    +
    constexpr iterator operator--(int) 
    +    requires concat-is-bidirectional<Const, Views...>;

    17 Effects: Equivalent to:

    -
    auto tmp = *this;
    ---*this;
    -return tmp;
    +
    auto tmp = *this;
    +--*this;
    +return tmp;
    -
    constexpr iterator& operator+=(difference_type n) 
    -    requires concat-is-random-access<Const, Views...>;
    +
    constexpr iterator& operator+=(difference_type n) 
    +    requires concat-is-random-access<Const, Views...>;

    18 Preconditions: @@ -1891,30 +1842,30 @@

    ?.?. Effects: Let i be it_.index(). Equivalent to:

    -
    if(n > 0) {
    -  advance-fwd<i>(get<i>(it_) - ranges::begin(get<i>(parent_->views_)), n);
    -} else if (n < 0) {
    -  advance-bwd<i>(get<i>(it_) - ranges::begin(get<i>(parent_->views_)), -n);
    -}
    -return *this;
    +
    if(n > 0) {
    +  advance-fwd<i>(get<i>(it_) - ranges::begin(get<i>(parent_->views_)), n);
    +} else if (n < 0) {
    +  advance-bwd<i>(get<i>(it_) - ranges::begin(get<i>(parent_->views_)), -n);
    +}
    +return *this;

    -
    constexpr iterator& operator-=(difference_type n) 
    -    requires concat-is-random-access<Const, Views...>;
    +
    constexpr iterator& operator-=(difference_type n) 
    +    requires concat-is-random-access<Const, Views...>;

    20 Effects: Equivalent to:

    -
    *this += -n;
    -return *this;
    +
    *this += -n;
    +return *this;
    -
    constexpr decltype(auto) operator[](difference_type n) const
    -    requires concat-is-random-access<Const, Views...>;
    +
    constexpr decltype(auto) operator[](difference_type n) const
    +    requires concat-is-random-access<Const, Views...>;

    21 Effects: Equivalent to:

    -
    return *((*this) + n);
    +
    return *((*this) + n);
    -
    friend constexpr bool operator==(const iterator& x, const iterator& y)
    -    requires(equality_comparable<iterator_t<maybe-const<Const, Views>>>&&...);
    +
    friend constexpr bool operator==(const iterator& x, const iterator& y)
    +    requires(equality_comparable<iterator_t<maybe-const<Const, Views>>>&&...);

    22 Preconditions: x.it_.valueless_by_exception() @@ -1922,30 +1873,30 @@

    ?.?. are each false.

    23 Effects: Equivalent to:

    -
    return x.it_ == y.it_;
    +
    return x.it_ == y.it_;

    -
    friend constexpr bool operator==(const iterator& it, default_sentinel_t);
    +
    friend constexpr bool operator==(const iterator& it, default_sentinel_t);

    24 Preconditions: it.it_.valueless_by_exception() is false.

    25 Effects: Equivalent to:

    -
    constexpr auto last_idx = sizeof...(Views) - 1;
    -return it.it_.index() == last_idx &&
    -       get<last_idx>(it.it_) == ranges::end(get<last_idx>(it.parent_->views_));
    +
    constexpr auto last_idx = sizeof...(Views) - 1;
    +return it.it_.index() == last_idx &&
    +       get<last_idx>(it.it_) == ranges::end(get<last_idx>(it.parent_->views_));
    -
    friend constexpr bool operator<(const iterator& x, const iterator& y)
    -    requires all-random-access<Const, Views...>;
    -friend constexpr bool operator>(const iterator& x, const iterator& y)
    -    requires all-random-access<Const, Views...>;
    -friend constexpr bool operator<=(const iterator& x, const iterator& y)
    -    requires all-random-access<Const, Views...>;
    -friend constexpr bool operator>=(const iterator& x, const iterator& y)
    -    requires all-random-access<Const, Views...>;
    -friend constexpr auto operator<=>(const iterator& x, const iterator& y)
    -   requires (all-random-access<Const, Views...> &&
    -    (three_way_comparable<maybe-const<Const, Views>> &&...));
    +
    friend constexpr bool operator<(const iterator& x, const iterator& y)
    +    requires all-random-access<Const, Views...>;
    +friend constexpr bool operator>(const iterator& x, const iterator& y)
    +    requires all-random-access<Const, Views...>;
    +friend constexpr bool operator<=(const iterator& x, const iterator& y)
    +    requires all-random-access<Const, Views...>;
    +friend constexpr bool operator>=(const iterator& x, const iterator& y)
    +    requires all-random-access<Const, Views...>;
    +friend constexpr auto operator<=>(const iterator& x, const iterator& y)
    +   requires (all-random-access<Const, Views...> &&
    +    (three_way_comparable<maybe-const<Const, Views>> &&...));

    26 Preconditions: x.it_.valueless_by_exception() @@ -1955,34 +1906,34 @@

    ?.?. op be the operator.

    28 Effects: Equivalent to:

    -
    return x.it_ op y.it_;
    +
    return x.it_ op y.it_;

    -
    friend constexpr iterator operator+(const iterator& it, difference_type n)
    -    requires concat-is-random-access<Const, Views...>;
    +
    friend constexpr iterator operator+(const iterator& it, difference_type n)
    +    requires concat-is-random-access<Const, Views...>;

    29 Preconditions: it.it_.valueless_by_exception() is false.

    30 Effects: Equivalent to:

    -
    return iterator{it} += n;
    +
    return iterator{it} += n;
    -
    friend constexpr iterator operator+(difference_type n, const iterator& it)
    -    requires concat-is-random-access<Const, Views...>;
    +
    friend constexpr iterator operator+(difference_type n, const iterator& it)
    +    requires concat-is-random-access<Const, Views...>;

    31 Effects: Equivalent to:

    -
    return it + n;
    +
    return it + n;
    -
    friend constexpr iterator operator-(const iterator& it, difference_type n)
    -    requires concat-is-random-access<Const, Views...>;
    +
    friend constexpr iterator operator-(const iterator& it, difference_type n)
    +    requires concat-is-random-access<Const, Views...>;

    32 Effects: Equivalent to:

    -
    return iterator{it} -= n;
    +
    return iterator{it} -= n;
    -
    friend constexpr difference_type operator-(const iterator& x, const iterator& y) 
    -    requires concat-is-random-access<Const, Views...>;
    +
    friend constexpr difference_type operator-(const iterator& x, const iterator& y) 
    +    requires concat-is-random-access<Const, Views...>;

    33 Preconditions: x.it_.valueless_by_exception() @@ -2004,21 +1955,22 @@

    ?.?. sizes of all the ranges get<i>(x.parent_->views_) for every integer iy < i < ix if there is any, and 0 -otherwise, of type make-unsigned-like-t<common_type_t<range_size_t<maybe-const<Const, Views>>...>>, -equivalent to

    -
    return dy + static_cast<difference_type>(s) + dx;
    +otherwise, of type +difference_type, equivalent +to

    +
    return dy + s + dx;
  • (34.2) otherwise, if ix < iy, equivalent to:

    -
    return -(y - x);
  • +
    return -(y - x);
  • (34.3) otherwise, equivalent to:

    -
    return get<ix>(x.it_) - get<iy>(y.it_);
  • +
    return get<ix>(x.it_) - get<iy>(y.it_);

    -
    friend constexpr difference_type operator-(const iterator& x, default_sentinel_t) 
    -    requires see below;
    +
    friend constexpr difference_type operator-(const iterator& x, default_sentinel_t) 
    +    requires see below;

    35 Preconditions: x.it_.valueless_by_exception() @@ -2030,52 +1982,53 @@

    ?.?. dx be ranges::distance(get<ix>(x.it_), ranges::end(get<ix>(x.parent_->views_))). Let s denote the sum of the sizes of all the ranges get<i>(x.parent_->views_) -For every integer ix < i < sizeof...(Views) +for every integer ix < i < sizeof...(Views) if there is any, and 0 -otherwise, of type make-unsigned-like-t<common_type_t<range_size_t<maybe-const<Const, Views>>...>>, -equivalent to

    -
    return -(dx + static_cast<difference_type>(s));
    +otherwise, of type +difference_type, equivalent +to

    +
    return -(dx + s);

    37 Remarks: Let V be the last element of the pack Views, the expression in the requires-clause is equivalent to:

    -
    (concat-is-random-access<Const, Views...> && sized_range<maybe-const<Const, V>>)
    +
    (concat-is-random-access<Const, Views...> && common_range<maybe-const<Const, V>>)

    -
    friend constexpr difference_type operator-(default_sentinel_t, const iterator& x) 
    -    requires see below;
    +
    friend constexpr difference_type operator-(default_sentinel_t, const iterator& x) 
    +    requires see below;

    38 Effects: Equivalent to:

    -
    return -(x - default_sentinel);
    +
    return -(x - default_sentinel);

    39 Remarks: Let V be the last element of the pack Views, the expression in the requires-clause is equivalent to:

    -
    (concat-is-random-access<Const, Views...> && sized_range<maybe-const<Const, V>>)
    +
    (concat-is-random-access<Const, Views...> && common_range<maybe-const<Const, V>>)
    -
    friend constexpr decltype(auto) iter_move(const iterator& it) noexcept(see below);
    +
    friend constexpr decltype(auto) iter_move(const iterator& it) noexcept(see below);

    40 Preconditions: it.it_.valueless_by_exception() is false.

    41 Effects: Equivalent to:

    -
    return std::visit(
    -    [](const auto& i) ->
    -        concat-rvalue-reference-t<maybe-const<Const, Views>...> { 
    -        return ranges::iter_move(i);
    -    },
    -    it.it_);
    +
    return std::visit(
    +    [](const auto& i) ->
    +        concat-rvalue-reference-t<maybe-const<Const, Views>...> { 
    +        return ranges::iter_move(i);
    +    },
    +    it.it_);

    42 Remarks: The exception specification is equivalent to:

    -
    ((is_nothrow_invocable_v<decltype(ranges::iter_move), 
    -                           const iterator_t<maybe-const<Const, Views>>&> &&
    -  is_nothrow_convertible_v<range_rvalue_reference_t<maybe-const<Const, Views>>,
    -                             common_reference_t<range_rvalue_reference_t<
    -                               maybe-const<Const, Views>>...>>) &&...)
    +
    ((is_nothrow_invocable_v<decltype(ranges::iter_move), 
    +                           const iterator_t<maybe-const<Const, Views>>&> &&
    +  is_nothrow_convertible_v<range_rvalue_reference_t<maybe-const<Const, Views>>,
    +                             common_reference_t<range_rvalue_reference_t<
    +                               maybe-const<Const, Views>>...>>) &&...)
    -
    friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below)
    -    requires see below;
    +
    friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below)
    +    requires see below;

    43 Preconditions: x.it_.valueless_by_exception() @@ -2083,26 +2036,26 @@

    ?.?. are each false.

    44 Effects: Equivalent to:

    -
    std::visit(
    -    [&](const auto& it1, const auto& it2) {
    -        if constexpr (is_same_v<decltype(it1), decltype(it2)>) {
    -            ranges::iter_swap(it1, it2);
    -        } else {
    -            ranges::swap(*x, *y);
    -        }
    -    },
    -    x.it_, y.it_);
    +
    std::visit(
    +    [&](const auto& it1, const auto& it2) {
    +        if constexpr (is_same_v<decltype(it1), decltype(it2)>) {
    +            ranges::iter_swap(it1, it2);
    +        } else {
    +            ranges::swap(*x, *y);
    +        }
    +    },
    +    x.it_, y.it_);

    45 Remarks: The exception specification is equivalent to

    -
    (noexcept(ranges::swap(*x, *y)) && ... && noexcept(ranges::iter_swap(its, its)))
    +
    (noexcept(ranges::swap(*x, *y)) && ... && noexcept(ranges::iter_swap(its, its)))

    where its is a pack of lvalues of type const iterator_t<maybe-const<Const, Views>> respectively.

    46 Remarks: The expression in the requires-clause is equivalent to

    -
    swappable_with<iter_reference_t<iterator>, iter_reference_t<iterator>> && 
    -(... && indirectly_swappable<iterator_t<maybe-const<Const, Views>>>)
    +
    swappable_with<iter_reference_t<iterator>, iter_reference_t<iterator>> && 
    +(... && indirectly_swappable<iterator_t<maybe-const<Const, Views>>>)

    5.4 Feature Test Macro

    Add the following macro definition to 17.3.2 @@ -2110,7 +2063,7 @@

    <version> synopsis, with the value selected by the editor to reflect the date of adoption of this paper:

    -
    #define __cpp_lib_ranges_concat  20XXXXL // also in <ranges>
    +
    #define __cpp_lib_ranges_concat  20XXXXL // also in <ranges>