Files
cppdraft_translate/cppdraft/range/concat.md
2025-10-25 03:02:53 +03:00

682 lines
42 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[range.concat]
# 25 Ranges library [[ranges]](./#ranges)
## 25.7 Range adaptors [[range.adaptors]](range.adaptors#range.concat)
### 25.7.18 Concat view [range.concat]
#### [25.7.18.1](#overview) Overview [[range.concat.overview]](range.concat.overview)
[1](#overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8697)
concat_view presents a view that concatenates all the underlying ranges[.](#overview-1.sentence-1)
[2](#overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8700)
The name views::concat denotes
a customization point object ([[customization.point.object]](customization.point.object "16.3.3.3.5Customization Point Object types"))[.](#overview-2.sentence-1)
Given a pack of subexpressions Es...,
the expression views::concat(Es...) is expression-equivalent to
- [(2.1)](#overview-2.1)
views::all(Es...) if Es is a pack with only one element
whose type models [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]"),
- [(2.2)](#overview-2.2)
otherwise, concat_view(Es...)[.](#overview-2.sentence-2)
[*Example [1](#overview-example-1)*: vector<int> v1{1, 2, 3}, v2{4, 5}, v3{};
array a{6, 7, 8};auto s = views::single(9);for (auto&& i : views::concat(v1, v2, v3, a, s)) { print("{} ", i); // prints 1 2 3 4 5 6 7 8 9} — *end example*]
#### [25.7.18.2](#view) Class template concat_view [[range.concat.view]](range.concat.view)
[🔗](#lib: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* = // *exposition only* common_reference_t<range_rvalue_reference_t<Rs>...>; template<class... Rs>concept [*concat-indirectly-readable*](#concept:concat-indirectly-readable "25.7.18.2Class template concat_­view[range.concat.view]") = *see below*; // *exposition only*template<class... Rs>concept [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]") = *see below*; // *exposition only*template<bool Const, class... Rs>concept [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]") = *see below*; // *exposition only*template<bool Const, class... Rs>concept [*concat-is-bidirectional*](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]") = *see below*; // *exposition only*template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0) &&[*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<Views...>class concat_view : public view_interface<concat_view<Views...>> { tuple<Views...> *views_*; // *exposition only*// [[range.concat.iterator]](#iterator "25.7.18.3Class concat_­view::iterator"), class template concat_view::*iterator*template<bool> class *iterator*; // *exposition only*public:constexpr concat_view() = default; constexpr explicit concat_view(Views... views); constexpr *iterator*<false> begin() requires (!([*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Views> && ...)); constexpr *iterator*<true> begin() constrequires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const Views> && ...) && [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<const Views...>; constexpr auto end() requires (!([*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Views> && ...)); constexpr auto end() constrequires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const Views> && ...) && [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<const Views...>; constexpr auto size() requires ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<Views> && ...); constexpr auto size() const requires ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const Views> && ...); }; template<class... R> concat_view(R&&...) -> concat_view<views::all_t<R>...>;}
[🔗](#concept:concat-indirectly-readable)
`template<class... Rs>
concept [concat-indirectly-readable](#concept:concat-indirectly-readable "25.7.18.2Class template concat_­view[range.concat.view]") = see below; // exposition only
`
[1](#view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8780)
The exposition-only [*concat-indirectly-readable*](#concept:concat-indirectly-readable "25.7.18.2Class template concat_­view[range.concat.view]") concept
is equivalent to:template<class Ref, class RRef, class It>concept [*concat-indirectly-readable-impl*](#concept:concat-indirectly-readable-impl "25.7.18.2Class template concat_­view[range.concat.view]") = // *exposition only*requires (const It it) {{ *it } -> [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<Ref>; { ranges::iter_move(it) } -> [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<RRef>; };
template<class... Rs>concept [*concat-indirectly-readable*](#concept:concat-indirectly-readable "25.7.18.2Class template concat_­view[range.concat.view]") = // *exposition only*[common_reference_with](concept.commonref#concept:common_reference_with "18.4.5Concept common_­reference_­with[concept.commonref]")<*concat-reference-t*<Rs...>&&, *concat-value-t*<Rs...>&> &&[common_reference_with](concept.commonref#concept:common_reference_with "18.4.5Concept common_­reference_­with[concept.commonref]")<*concat-reference-t*<Rs...>&&, *concat-rvalue-reference-t*<Rs...>&&> &&[common_reference_with](concept.commonref#concept:common_reference_with "18.4.5Concept common_­reference_­with[concept.commonref]")<*concat-rvalue-reference-t*<Rs...>&&, *concat-value-t*<Rs...> const&> &&([*concat-indirectly-readable-impl*](#concept:concat-indirectly-readable-impl "25.7.18.2Class template concat_­view[range.concat.view]")<*concat-reference-t*<Rs...>, *concat-rvalue-reference-t*<Rs...>,
iterator_t<Rs>> && ...);
[🔗](#concept:concatable)
`template<class... Rs>
concept [concatable](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]") = see below; // exposition only
`
[2](#view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8811)
The exposition-only [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]") concept is equivalent to:template<class... Rs>concept [*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]") = requires { // *exposition only*typename *concat-reference-t*<Rs...>; typename *concat-value-t*<Rs...>; typename *concat-rvalue-reference-t*<Rs...>; } && [*concat-indirectly-readable*](#concept:concat-indirectly-readable "25.7.18.2Class template concat_­view[range.concat.view]")<Rs...>;
[🔗](#concept:concat-is-random-access)
`template<bool Const, class... Rs>
concept [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]") = see below; // exposition only
`
[3](#view-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8829)
Let Fs be the pack that consists of all elements of Rs except the last element,
then *concat-is-random-access* is equivalent to:template<bool Const, class... Rs>concept [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]") = // *exposition only*[*all-random-access*](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Rs...> &&([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, Fs>> && ...);
[🔗](#concept:concat-is-bidirectional)
`template<bool Const, class... Rs>
concept [concat-is-bidirectional](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]") = see below; // exposition only
`
[4](#view-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8848)
Let Fs be the pack that consists of all elements of Rs except the last element,
then *concat-is-bidirectional* is equivalent to:template<bool Const, class... Rs>concept [*concat-is-bidirectional*](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]") = // *exposition only*[*all-bidirectional*](range.adaptor.helpers#concept:all-bidirectional "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Rs...> &&([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<Const, Fs>> && ...);
[🔗](#lib:concat_view,constructor)
`constexpr explicit concat_view(Views... views);
`
[5](#view-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8867)
*Effects*: Initializes *views_* with std::move(views)...[.](#view-5.sentence-1)
[🔗](#lib:begin,concat_view)
`constexpr iterator<false> begin() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Views> && ...));
constexpr iterator<true> begin() const
requires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const Views> && ...) && [concatable](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<const Views...>;
`
[6](#view-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8880)
*Effects*: Let *is-const* betrue for the const-qualified overload, andfalse otherwise[.](#view-6.sentence-1)
Equivalent to:*iterator*<*is-const*> it(this, in_place_index<0>, ranges::begin(std::get<0>(*views_*)));
it.template *satisfy*<0>();return it;
[🔗](#lib:end,concat_view)
`constexpr auto end() requires (!([simple-view](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Views> && ...));
constexpr auto end() const
requires ([range](range.range#concept:range "25.4.2Ranges[range.range]")<const Views> && ...) && [concatable](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<const Views...>;
`
[7](#view-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8901)
*Effects*: Let *is-const* betrue for the const-qualified overload, andfalse otherwise[.](#view-7.sentence-1)
Equivalent to:constexpr auto N = sizeof...(Views);if constexpr ([common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*maybe-const*<*is-const*, Views...[N - 1]>>) {return *iterator*<*is-const*>(this, in_place_index<N - 1>,
ranges::end(std::get<N - 1>(*views_*)));} else {return default_sentinel;}
[🔗](#lib:size,concat_view)
`constexpr auto size() requires ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<Views> && ...);
constexpr auto size() const requires ([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<const Views> && ...);
`
[8](#view-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L8925)
*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_*));
#### [25.7.18.3](#iterator) Class concat_view::*iterator* [[range.concat.iterator]](range.concat.iterator)
[🔗](#lib:iterator,concat_view)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")... Views>requires ([view](range.view#concept:view "25.4.5Views[range.view]")<Views> && ...) && (sizeof...(Views) > 0) &&[*concatable*](#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<Views...>template<bool Const>class concat_view<Views...>::*iterator* {public:using iterator_category = *see below*; // not always presentusing 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<size_t N>constexpr void *satisfy*(); // *exposition only*template<size_t N>constexpr void *prev*(); // *exposition only*template<size_t N>constexpr void *advance-fwd*(difference_type offset, // *exposition only* difference_type steps); template<size_t N>constexpr void *advance-bwd*(difference_type offset, // *exposition only* difference_type steps); template<class... Args>constexpr explicit *iterator*(*maybe-const*<Const, concat_view>* parent, // *exposition only* Args&&... args)requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<*base-iter*, Args&&...>; public:*iterator*() = default; constexpr *iterator*(*iterator*<!Const> i)requires Const && ([convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<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*](range.adaptor.helpers#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; constexpr *iterator*& operator--()requires [*concat-is-bidirectional*](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; constexpr *iterator* operator--(int)requires [*concat-is-bidirectional*](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; constexpr *iterator*& operator+=(difference_type n)requires [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; constexpr *iterator*& operator-=(difference_type n)requires [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; constexpr decltype(auto) operator[](difference_type n) constrequires [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; friend constexpr bool operator==(const *iterator*& x, const *iterator*& y)requires ([equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<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*](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; friend constexpr bool operator>(const *iterator*& x, const *iterator*& y)requires [*all-random-access*](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; friend constexpr bool operator<=(const *iterator*& x, const *iterator*& y)requires [*all-random-access*](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; friend constexpr bool operator>=(const *iterator*& x, const *iterator*& y)requires [*all-random-access*](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>; friend constexpr auto operator<=>(const *iterator*& x, const *iterator*& y)requires ([*all-random-access*](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> &&([three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<iterator_t<*maybe-const*<Const, Views>>> && ...)); friend constexpr *iterator* operator+(const *iterator*& it, difference_type n)requires [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; friend constexpr *iterator* operator+(difference_type n, const *iterator*& it)requires [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; friend constexpr *iterator* operator-(const *iterator*& it, difference_type n)requires [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>; friend constexpr difference_type operator-(const *iterator*& x, const *iterator*& y)requires [*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<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-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9035)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#iterator-1.1)
If[*concat-is-random-access*](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...> is modeled,
then iterator_concept denotes random_access_iterator_tag[.](#iterator-1.1.sentence-1)
- [(1.2)](#iterator-1.2)
Otherwise, if[*concat-is-bidirectional*](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...> is modeled,
then iterator_concept denotes bidirectional_iterator_tag[.](#iterator-1.2.sentence-1)
- [(1.3)](#iterator-1.3)
Otherwise, if[*all-forward*](range.adaptor.helpers#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled,
then iterator_concept denotes forward_iterator_tag[.](#iterator-1.3.sentence-1)
- [(1.4)](#iterator-1.4)
Otherwise, iterator_concept denotes input_iterator_tag[.](#iterator-1.4.sentence-1)
[2](#iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9054)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category is defined
if and only if[*all-forward*](range.adaptor.helpers#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> is modeled[.](#iterator-2.sentence-1)
In that case,*iterator*::iterator_category is defined as follows:
- [(2.1)](#iterator-2.1)
Ifis_reference_v<*concat-reference-t*<*maybe-const*<Const, Views>...>> is false,
then iterator_category denotes input_iterator_tag[.](#iterator-2.1.sentence-1)
- [(2.2)](#iterator-2.2)
Otherwise,
let Cs denote the pack of typesiterator_traits<iterator_t<*maybe-const*<Const, Views>>>::iterator_category...[.](#iterator-2.2.sentence-1)
* [(2.2.1)](#iterator-2.2.1)
If([derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<Cs, random_access_iterator_tag> && ...) && *concat-is-random-access*<Const, Views...> is true,iterator_category denotes random_access_iterator_tag[.](#iterator-2.2.1.sentence-1)
* [(2.2.2)](#iterator-2.2.2)
Otherwise, if([derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<Cs, bidirectional_iterator_tag> && ...) && *concat-is-bidirectional*<Const, Views...> is true,iterator_category denotes bidirectional_iterator_tag[.](#iterator-2.2.2.sentence-1)
* [(2.2.3)](#iterator-2.2.3)
Otherwise, if([derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<Cs, forward_iterator_tag> && ...) is true,iterator_category denotes forward_iterator_tag[.](#iterator-2.2.3.sentence-1)
* [(2.2.4)](#iterator-2.2.4)
Otherwise, iterator_category denotes input_iterator_tag[.](#iterator-2.2.4.sentence-1)
[🔗](#lib:satisfy,concat_view::iterator)
`template<size_t N>
constexpr void satisfy();
`
[3](#iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9100)
*Effects*: Equivalent to:if constexpr (N < (sizeof...(Views) - 1)) {if (std::get<N>(*it_*) == ranges::end(std::get<N>(*parent_*->*views_*))) {*it_*.template emplace<N + 1>(ranges::begin(std::get<N + 1>(*parent_*->*views_*))); *satisfy*<N + 1>(); }}
[🔗](#lib:prev,concat_view::iterator)
`template<size_t N>
constexpr void prev();
`
[4](#iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9120)
*Effects*: Equivalent to:if constexpr (N == 0) {--std::get<0>(*it_*);} else {if (std::get<N>(*it_*) == ranges::begin(std::get<N>(*parent_*->*views_*))) {*it_*.template emplace<N - 1>(ranges::end(std::get<N - 1>(*parent_*->*views_*))); *prev*<N - 1>(); } else {--std::get<N>(*it_*); }}
[🔗](#lib:advance-fwd,concat_view::iterator)
`template<size_t N>
constexpr void advance-fwd(difference_type offset, difference_type steps);
`
[5](#iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9144)
*Effects*: Equivalent to:using underlying_diff_type = iter_difference_t<variant_alternative_t<N, *base-iter*>>;if constexpr (N == sizeof...(Views) - 1) { std::get<N>(*it_*) += static_cast<underlying_diff_type>(steps);} else {auto n_size = ranges::distance(std::get<N>(*parent_*->*views_*)); if (offset + steps < n_size) { std::get<N>(*it_*) += static_cast<underlying_diff_type>(steps); } else {*it_*.template emplace<N + 1>(ranges::begin(std::get<N + 1>(*parent_*->*views_*))); *advance-fwd*<N + 1>(0, offset + steps - n_size); }}
[🔗](#lib:advance-bwd,concat_view::iterator)
`template<size_t N>
constexpr void advance-bwd(difference_type offset, difference_type steps);
`
[6](#iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9170)
*Effects*: Equivalent to:using underlying_diff_type = iter_difference_t<variant_alternative_t<N, *base-iter*>>;if constexpr (N == 0) { std::get<N>(*it_*) -= static_cast<underlying_diff_type>(steps);} else {if (offset >= steps) { std::get<N>(*it_*) -= static_cast<underlying_diff_type>(steps); } else {auto prev_size = ranges::distance(std::get<N - 1>(*parent_*->*views_*)); *it_*.template emplace<N - 1>(ranges::end(std::get<N - 1>(*parent_*->*views_*))); *advance-bwd*<N - 1>(prev_size, steps - offset); }}
[🔗](#lib:concat_view::iterator,constructor)
`template<class... Args>
constexpr explicit iterator(maybe-const<Const, concat_view>* parent,
Args&&... args)
requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<base-iter, Args&&...>;
`
[7](#iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9198)
*Effects*: Initializes *parent_* with parent, and
initializes *it_* with std::forward<Args>(args)...[.](#iterator-7.sentence-1)
[🔗](#lib:concat_view::iterator,constructor_)
`constexpr iterator(iterator<!Const> it)
requires Const &&
([convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<Views>, iterator_t<const Views>> && ...);
`
[8](#iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9212)
*Preconditions*: it.*it_*.valueless_by_exception() is false[.](#iterator-8.sentence-1)
[9](#iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9216)
*Effects*: Initializes *parent_* with it.*parent_*, and
let i be it.*it_*.index(),
initializes *it_* with*base-iter*(in_place_index<i>, std::get<i>(std::move(it.*it_*)))[.](#iterator-9.sentence-1)
[🔗](#lib:operator*,concat_view::iterator)
`constexpr decltype(auto) operator*() const;
`
[10](#iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9230)
*Preconditions*: *it_*.valueless_by_exception() is false[.](#iterator-10.sentence-1)
[11](#iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9234)
*Effects*: Equivalent to:using reference = *concat-reference-t*<*maybe-const*<Const, Views>...>;return std::visit([](auto&& it) -> reference { return *it; }, *it_*);
[🔗](#lib:operator++,concat_view::iterator)
`constexpr iterator& operator++();
`
[12](#iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9250)
*Preconditions*: *it_*.valueless_by_exception() is false[.](#iterator-12.sentence-1)
[13](#iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9254)
*Effects*: Let i be *it_*.index()[.](#iterator-13.sentence-1)
Equivalent to:++std::get<i>(*it_*);*satisfy*<i>();return *this;
[🔗](#lib:operator++,concat_view::iterator_)
`constexpr void operator++(int);
`
[14](#iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9271)
*Effects*: Equivalent to:++*this;
[🔗](#lib:operator++,concat_view::iterator__)
`constexpr iterator operator++(int)
requires [all-forward](range.adaptor.helpers#concept:all-forward "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
`
[15](#iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9286)
*Effects*: Equivalent to:auto tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,concat_view::iterator)
`constexpr iterator& operator--()
requires [concat-is-bidirectional](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[16](#iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9303)
*Preconditions*: *it_*.valueless_by_exception() is false[.](#iterator-16.sentence-1)
[17](#iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9307)
*Effects*: Let i be *it_*.index()[.](#iterator-17.sentence-1)
Equivalent to:*prev*<i>();return *this;
[🔗](#lib:operator--,concat_view::iterator_)
`constexpr iterator operator--(int)
requires [concat-is-bidirectional](#concept:concat-is-bidirectional "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[18](#iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9324)
*Effects*: Equivalent to:auto tmp = *this;--*this;return tmp;
[🔗](#lib:operator+=,concat_view::iterator)
`constexpr iterator& operator+=(difference_type n)
requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[19](#iterator-19)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9341)
*Preconditions*: *it_*.valueless_by_exception() is false[.](#iterator-19.sentence-1)
[20](#iterator-20)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9345)
*Effects*: Let i be *it_*.index()[.](#iterator-20.sentence-1)
Equivalent to:if (n > 0) {*advance-fwd*<i>(std::get<i>(*it_*) - ranges::begin(std::get<i>(*parent_*->*views_*)), n);} else if (n < 0) {*advance-bwd*<i>(std::get<i>(*it_*) - ranges::begin(std::get<i>(*parent_*->*views_*)), -n);}return *this;
[🔗](#lib:operator-=,concat_view::iterator)
`constexpr iterator& operator-=(difference_type n)
requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[21](#iterator-21)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9366)
*Effects*: Equivalent to:*this += -n;return *this;
[🔗](#lib:operator%5b%5d,concat_view::iterator)
`constexpr decltype(auto) operator[](difference_type n) const
requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[22](#iterator-22)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9382)
*Effects*: Equivalent to:return *((*this) + n);
[🔗](#lib:operator==,concat_view::iterator)
`friend constexpr bool operator==(const iterator& x, const iterator& y)
requires ([equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<iterator_t<maybe-const<Const, Views>>> && ...);
`
[23](#iterator-23)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9397)
*Preconditions*: x.*it_*.valueless_by_exception() andy.*it_*.valueless_by_exception() are each false[.](#iterator-23.sentence-1)
[24](#iterator-24)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9402)
*Effects*: Equivalent to:return x.*it_* == y.*it_*;
[🔗](#lib:operator==,concat_view::iterator_)
`friend constexpr bool operator==(const iterator& it, default_sentinel_t);
`
[25](#iterator-25)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9416)
*Preconditions*: it.*it_*.valueless_by_exception() is false[.](#iterator-25.sentence-1)
[26](#iterator-26)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9420)
*Effects*: Equivalent to:constexpr auto last_idx = sizeof...(Views) - 1;return it.*it_*.index() == last_idx && std::get<last_idx>(it.*it_*) == ranges::end(std::get<last_idx>(it.*parent_*->*views_*));
[🔗](#lib:operator%3c,concat_view::iterator)
`friend constexpr bool operator<(const iterator& x, const iterator& y)
requires [all-random-access](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
friend constexpr bool operator>(const iterator& x, const iterator& y)
requires [all-random-access](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
friend constexpr bool operator<=(const iterator& x, const iterator& y)
requires [all-random-access](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
friend constexpr bool operator>=(const iterator& x, const iterator& y)
requires [all-random-access](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...>;
friend constexpr auto operator<=>(const iterator& x, const iterator& y)
requires ([all-random-access](range.adaptor.helpers#concept:all-random-access "25.7.5Range adaptor helpers[range.adaptor.helpers]")<Const, Views...> &&
([three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4Concept three_­way_­comparable[cmp.concept]")<iterator_t<maybe-const<Const, Views>>> && ...));
`
[27](#iterator-27)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9446)
*Preconditions*: x.*it_*.valueless_by_exception() andy.*it_*.valueless_by_exception() are each false[.](#iterator-27.sentence-1)
[28](#iterator-28)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9451)
Let op be the operator[.](#iterator-28.sentence-1)
[29](#iterator-29)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9454)
*Effects*: Equivalent to:return x.*it_* op y.*it_*;
[🔗](#lib:operator+,concat_view::iterator)
`friend constexpr iterator operator+(const iterator& it, difference_type n)
requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[30](#iterator-30)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9469)
*Effects*: Equivalent to:auto temp = it;
temp += n;return temp;
[🔗](#lib:operator+,concat_view::iterator_)
`friend constexpr iterator operator+(difference_type n, const iterator& it)
requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[31](#iterator-31)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9486)
*Effects*: Equivalent to:return it + n;
[🔗](#lib:operator-,concat_view::iterator)
`friend constexpr iterator operator-(const iterator& it, difference_type n)
requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[32](#iterator-32)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9501)
*Effects*: Equivalent to:auto temp = it;
temp -= n;return temp;
[🔗](#lib:operator-,concat_view::iterator_)
`friend constexpr difference_type operator-(const iterator& x, const iterator& y)
requires [concat-is-random-access](#concept:concat-is-random-access "25.7.18.2Class template concat_­view[range.concat.view]")<Const, Views...>;
`
[33](#iterator-33)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9518)
*Preconditions*: x.*it_*.valueless_by_exception() andy.*it_*.valueless_by_exception() are each false[.](#iterator-33.sentence-1)
[34](#iterator-34)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9523)
*Effects*: Letix denote x.*it_*.index() andiy denote y.*it_*.index()[.](#iterator-34.sentence-1)
- [(34.1)](#iterator-34.1)
If ix > iy, letdy beranges::distance(std::get<iy>(y.*it_*), ranges::end(std::get<iy>(y.*parent_*->*views_*))),dx beranges::distance(ranges::begin(std::get<ix>(x.*parent_*->*views_*)), std::get<ix>(x.*it_*)). Let s denote the sum of the sizes of all the rangesstd::get<i>(x.*parent_*->*views_*) for every integer i in the range
[iy + 1, ix)
if there is any, and0 otherwise,
of type difference_type,
equivalent to:return dy + s + dx;
- [(34.2)](#iterator-34.2)
otherwise, if ix < iy is true,
equivalent to:return -(y - x);
- [(34.3)](#iterator-34.3)
otherwise, equivalent to:return std::get<ix>(x.*it_*) - std::get<iy>(y.*it_*);
[🔗](#lib:operator-,concat_view::iterator__)
`friend constexpr difference_type operator-(const iterator& x, default_sentinel_t)
requires see below;
`
[35](#iterator-35)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9571)
*Preconditions*: x.*it_*.valueless_by_exception() is false[.](#iterator-35.sentence-1)
[36](#iterator-36)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9575)
*Effects*: Letix denote x.*it_*.index(),dx beranges::distance(std::get<ix>(x.*it_*), ranges::end(std::get<ix>(x.*parent_*->*views_*)))[.](#iterator-36.sentence-1)
Let s denote the sum of the sizes of all the rangesstd::get<i>(x.*parent_*->*views_*) for every integer i in the range
[ix + 1, sizeof...(Views))
if there is any, and0 otherwise,
of type difference_type,
equivalent to:return -(dx + s);
[37](#iterator-37)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9594)
*Remarks*: Let Fs be the pack that consists of all elements of Views except the first element,
the expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") is equivalent to:([sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<*maybe-const*<Const, Views>>,
iterator_t<*maybe-const*<Const, Views>>> && ...) &&([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<*maybe-const*<Const, Fs>> && ...)
[🔗](#lib:operator-,concat_view::iterator___)
`friend constexpr difference_type operator-(default_sentinel_t, const iterator& x)
requires see below;
`
[38](#iterator-38)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9614)
*Effects*: Equivalent to:return -(x - default_sentinel);
[39](#iterator-39)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9621)
*Remarks*: Let Fs be the pack that consists of all elements of Views except the first element,
the expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") is equivalent to:([sized_sentinel_for](iterator.concept.sizedsentinel#concept:sized_sentinel_for "24.3.4.8Concept sized_­sentinel_­for[iterator.concept.sizedsentinel]")<sentinel_t<*maybe-const*<Const, Views>>,
iterator_t<*maybe-const*<Const, Views>>> && ...) &&([sized_range](range.sized#concept:sized_range "25.4.4Sized ranges[range.sized]")<*maybe-const*<Const, Fs>> && ...)
[🔗](#lib:iter_move,concat_view::iterator)
`friend constexpr decltype(auto) iter_move(const iterator& it) noexcept(see below);
`
[40](#iterator-40)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9639)
*Preconditions*: it.*it_*.valueless_by_exception() is false[.](#iterator-40.sentence-1)
[41](#iterator-41)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9643)
*Effects*: Equivalent to:return std::visit([](const auto& i)-> *concat-rvalue-reference-t*<*maybe-const*<Const, Views>...> {return ranges::iter_move(i); },
it.*it_*);
[42](#iterator-42)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9654)
*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>>, *concat-rvalue-reference-t*<*maybe-const*<Const, Views>...>>) &&...)
[🔗](#lib:iter_swap,concat_view::iterator)
`friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(see below)
requires see below;
`
[43](#iterator-43)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9673)
*Preconditions*: x.*it_*.valueless_by_exception() andy.*it_*.valueless_by_exception() are each false[.](#iterator-43.sentence-1)
[44](#iterator-44)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9678)
*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_*);
[45](#iterator-45)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L9692)
*Remarks*: The exception specification is equivalent to(noexcept(ranges::swap(*x, *y)) && ... && noexcept(ranges::iter_swap(its, its))) where its is a pack of lvalues of typeconst iterator_t<*maybe-const*<Const, Views>> respectively[.](#iterator-45.sentence-1)
The expression in the [*requires-clause*](temp.pre#nt:requires-clause "13.1Preamble[temp.pre]") is equivalent to[swappable_with](concept.swappable#concept:swappable_with "18.4.9Concept swappable[concept.swappable]")<iter_reference_t<*iterator*>, iter_reference_t<*iterator*>> &&(... && [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<iterator_t<*maybe-const*<Const, Views>>>)