Files
2025-10-25 03:02:53 +03:00

366 lines
30 KiB
Markdown
Raw Permalink 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.join.with]
# 25 Ranges library [[ranges]](./#ranges)
## 25.7 Range adaptors [[range.adaptors]](range.adaptors#range.join.with)
### 25.7.15 Join with view [range.join.with]
#### [25.7.15.1](#overview) Overview [[range.join.with.overview]](range.join.with.overview)
[1](#overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7186)
join_with_view takes a view and a delimiter, and
flattens the view,
inserting every element of the delimiter
in between elements of the view[.](#overview-1.sentence-1)
The delimiter can be a single element or a view of elements[.](#overview-1.sentence-2)
[2](#overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7193)
The name views::join_with denotes
a range adaptor object ([[range.adaptor.object]](range.adaptor.object "25.7.2Range adaptor objects"))[.](#overview-2.sentence-1)
Given subexpressions E and F,
the expression views::join_with(E, F) is expression-equivalent tojoin_with_view(E, F)[.](#overview-2.sentence-2)
[3](#overview-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7201)
[*Example [1](#overview-example-1)*: vector<string> vs = {"the", "quick", "brown", "fox"};for (char c : vs | views::join_with('-')) { cout << c;}// The above prints the-quick-brown-fox — *end example*]
#### [25.7.15.2](#view) Class template join_with_view [[range.join.with.view]](range.join.with.view)
[🔗](#lib:join_with_view)
namespace std::ranges {template<class R>concept [*bidirectional-common*](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]") = [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<R> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<R>; // *exposition only*template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<V>>&& [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern>&& [*concatable*](range.concat.view#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<V>, Pattern>class join_with_view : public view_interface<join_with_view<V, Pattern>> {using *InnerRng* = range_reference_t<V>; // *exposition only* V *base_* = V(); // *exposition only**non-propagating-cache*<iterator_t<V>> *outer_it_*; // *exposition only*, present only// when ![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>*non-propagating-cache*<remove_cv_t<*InnerRng*>> *inner_*; // *exposition only*, present only// if is_reference_v<*InnerRng*> is false Pattern *pattern_* = Pattern(); // *exposition only*// [[range.join.with.iterator]](#iterator "25.7.15.3Class template join_­with_­view::iterator"), class template join_with_view::*iterator*template<bool Const> struct *iterator*; // *exposition only*// [[range.join.with.sentinel]](#sentinel "25.7.15.4Class template join_­with_­view::sentinel"), class template join_with_view::*sentinel*template<bool Const> struct *sentinel*; // *exposition only*public: join_with_view()requires [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<V> && [default_initializable](concept.default.init#concept:default_initializable "18.4.12Concept default_­initializable[concept.default.init]")<Pattern> = default; constexpr explicit join_with_view(V base, Pattern pattern); template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R>requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<V, views::all_t<R>> &&[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<Pattern, single_view<range_value_t<*InnerRng*>>>constexpr explicit join_with_view(R&& r, range_value_t<*InnerRng*> e); constexpr V base() const & requires [copy_constructible](concept.copyconstructible#concept:copy_constructible "18.4.14Concept copy_­constructible[concept.copyconstructible]")<V> { return *base_*; }constexpr V base() && { return std::move(*base_*); }constexpr auto begin() {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V>) {constexpr bool use_const =[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && is_reference_v<*InnerRng*> && [*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Pattern>; return *iterator*<use_const>{*this, ranges::begin(*base_*)}; }else {*outer_it_* = ranges::begin(*base_*); return *iterator*<false>{*this}; }}constexpr auto begin() constrequires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> &&[forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const Pattern> && is_reference_v<range_reference_t<const V>> &&[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<const V>> &&[*concatable*](range.concat.view#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<const V>, const Pattern> {return *iterator*<true>{*this, ranges::begin(*base_*)}; }constexpr auto end() {if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<V> && is_reference_v<*InnerRng*> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*InnerRng*> &&[common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<*InnerRng*>)return *iterator*<[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Pattern>>{*this, ranges::end(*base_*)}; elsereturn *sentinel*<[*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<V> && [*simple-view*](range.utility.helpers#concept:simple-view "25.5.2Helper concepts[range.utility.helpers]")<Pattern>>{*this}; }constexpr auto end() constrequires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const V> && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<const Pattern> && is_reference_v<range_reference_t<const V>> &&[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<const V>> &&[*concatable*](range.concat.view#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<const V>, const Pattern> {using InnerConstRng = range_reference_t<const V>; if constexpr ([forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<InnerConstRng> &&[common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<const V> && [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]")<InnerConstRng>)return *iterator*<true>{*this, ranges::end(*base_*)}; elsereturn *sentinel*<true>{*this}; }}; template<class R, class P> join_with_view(R&&, P&&) -> join_with_view<views::all_t<R>, views::all_t<P>>; template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R> join_with_view(R&&, range_value_t<range_reference_t<R>>)-> join_with_view<views::all_t<R>, single_view<range_value_t<range_reference_t<R>>>>;}
[🔗](#lib:join_with_view,constructor)
`constexpr explicit join_with_view(V base, Pattern pattern);
`
[1](#view-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7311)
*Effects*: Initializes *base_* with std::move(base) and*pattern_* with std::move(pattern)[.](#view-1.sentence-1)
[🔗](#lib:join_with_view,constructor_)
`template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") R>
requires [constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<V, views::all_t<R>> &&
[constructible_from](concept.constructible#concept:constructible_from "18.4.11Concept constructible_­from[concept.constructible]")<Pattern, single_view<range_value_t<InnerRng>>>
constexpr explicit join_with_view(R&& r, range_value_t<InnerRng> e);
`
[2](#view-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7326)
*Effects*: Initializes *base_* with views::all(std::forward<R>(r)) and*pattern_* with views::single(std::move(e))[.](#view-2.sentence-1)
#### [25.7.15.3](#iterator) Class template join_with_view::*iterator* [[range.join.with.iterator]](range.join.with.iterator)
[🔗](#lib:join_with_view::iterator)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<V>>&& [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> && [*concatable*](range.concat.view#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<V>, Pattern>template<bool Const>class join_with_view<V, Pattern>::*iterator* {using *Parent* = *maybe-const*<Const, join_with_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only*using *InnerBase* = range_reference_t<*Base*>; // *exposition only*using *PatternBase* = *maybe-const*<Const, Pattern>; // *exposition only*using *OuterIter* = iterator_t<*Base*>; // *exposition only*using *InnerIter* = iterator_t<*InnerBase*>; // *exposition only*using *PatternIter* = iterator_t<*PatternBase*>; // *exposition only*static constexpr bool *ref-is-glvalue* = is_reference_v<*InnerBase*>; // *exposition only**Parent** *parent_* = nullptr; // *exposition only**OuterIter* *outer_it_* = *OuterIter*(); // *exposition only*, present only// if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") variant<*PatternIter*, *InnerIter*> *inner_it_*; // *exposition only*constexpr *iterator*(*Parent*& parent, *OuterIter* outer)requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>; // *exposition only*constexpr explicit *iterator*(*Parent*& parent)requires (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*>); // *exposition only*constexpr *OuterIter*& *outer*(); // *exposition only*constexpr const *OuterIter*& *outer*() const; // *exposition only*constexpr auto& *update-inner*(); // *exposition only*constexpr auto& *get-inner*(); // *exposition only*constexpr void *satisfy*(); // *exposition only*public:using iterator_concept = *see below*; using iterator_category = *see below*; // not always presentusing value_type = *see below*; using difference_type = *see below*; *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<V>, *OuterIter*> &&[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<*InnerRng*>, *InnerIter*> &&[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<Pattern>, *PatternIter*>; constexpr decltype(auto) operator*() const; constexpr *iterator*& operator++(); constexpr void operator++(int); constexpr *iterator* operator++(int)requires *ref-is-glvalue* && [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11Concept forward_­iterator[iterator.concept.forward]")<*OuterIter*> &&[forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11Concept forward_­iterator[iterator.concept.forward]")<*InnerIter*>; constexpr *iterator*& operator--()requires *ref-is-glvalue* && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*> &&[*bidirectional-common*](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<*InnerBase*> && [*bidirectional-common*](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<*PatternBase*>; constexpr *iterator* operator--(int)requires *ref-is-glvalue* && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<*Base*> &&[*bidirectional-common*](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<*InnerBase*> && [*bidirectional-common*](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<*PatternBase*>; friend constexpr bool operator==(const *iterator*& x, const *iterator*& y)requires *ref-is-glvalue* && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<*Base*> &&[equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<*InnerIter*>; friend constexpr decltype(auto) iter_move(const *iterator*& x) {using rvalue_reference = common_reference_t< iter_rvalue_reference_t<*InnerIter*>,
iter_rvalue_reference_t<*PatternIter*>>; return visit<rvalue_reference>(ranges::iter_move, x.*inner_it_*); }friend constexpr void iter_swap(const *iterator*& x, const *iterator*& y)requires [indirectly_swappable](alg.req.ind.swap#concept:indirectly_swappable "24.3.7.4Concept indirectly_­swappable[alg.req.ind.swap]")<*InnerIter*, *PatternIter*> { visit(ranges::iter_swap, x.*inner_it_*, y.*inner_it_*); }};}
[1](#iterator-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7414)
*iterator*::iterator_concept is defined as follows:
- [(1.1)](#iterator-1.1)
If *ref-is-glvalue* is true,*Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]"), and*InnerBase* and *PatternBase* each model [*bidirectional-common*](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#iterator-1.1.sentence-1)
- [(1.2)](#iterator-1.2)
Otherwise, if *ref-is-glvalue* is true and*Base* and *InnerBase* each model [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]"),
then iterator_concept denotes forward_iterator_tag[.](#iterator-1.2.sentence-1)
- [(1.3)](#iterator-1.3)
Otherwise, iterator_concept denotes input_iterator_tag[.](#iterator-1.3.sentence-1)
[2](#iterator-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7431)
The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4The typedef specifier[dcl.typedef]") iterator_category is defined
if and only if *ref-is-glvalue* is true, and*Base* and *InnerBase* each model [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#iterator-2.sentence-1)
In that case,*iterator*::iterator_category is defined as follows:
- [(2.1)](#iterator-2.1)
Let *OUTERC* denoteiterator_traits<*OuterIter*>::iterator_category,
let *INNERC* denoteiterator_traits<*InnerIter*>::iterator_category, and
let *PATTERNC* denoteiterator_traits<*PatternIter*>::iterator_category[.](#iterator-2.1.sentence-1)
- [(2.2)](#iterator-2.2)
Ifis_reference_v<common_reference_t<iter_reference_t<*InnerIter*>,
iter_reference_t<*PatternIter*>>> is false,iterator_category denotes input_iterator_tag[.](#iterator-2.2.sentence-1)
- [(2.3)](#iterator-2.3)
Otherwise,
if *OUTERC*, *INNERC*, and *PATTERNC* each model [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<bidirectional_iterator_tag> and *InnerBase* and *PatternBase* each model [common_range](range.refinements#concept:common_range "25.4.6Other range refinements[range.refinements]"),iterator_category denotes bidirectional_iterator_tag[.](#iterator-2.3.sentence-1)
- [(2.4)](#iterator-2.4)
Otherwise,
if *OUTERC*, *INNERC*, and *PATTERNC* each model [derived_from](concept.derived#concept:derived_from "18.4.3Concept derived_­from[concept.derived]")<forward_iterator_tag>,iterator_category denotes forward_iterator_tag[.](#iterator-2.4.sentence-1)
- [(2.5)](#iterator-2.5)
Otherwise, iterator_category denotes input_iterator_tag[.](#iterator-2.5.sentence-1)
[3](#iterator-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7469)
*iterator*::value_type denotes the type:common_type_t<iter_value_t<*InnerIter*>, iter_value_t<*PatternIter*>>
[4](#iterator-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7475)
*iterator*::difference_type denotes the type:common_type_t< iter_difference_t<*OuterIter*>,
iter_difference_t<*InnerIter*>,
iter_difference_t<*PatternIter*>>
[🔗](#lib:outer,join_with_view::iterator)
`constexpr OuterIter& outer();
constexpr const OuterIter& outer() const;
`
[5](#iterator-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7491)
*Returns*: *outer_it_* if *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]");
otherwise, **parent_*->*outer_it_*[.](#iterator-5.sentence-1)
[🔗](#lib:update-inner,join_with_view::iterator)
`constexpr auto& update-inner();
`
[6](#iterator-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7503)
*Effects*: Equivalent to:if constexpr (*ref-is-glvalue*)return *as-lvalue*(**outer*());elsereturn *parent_*->*inner_*.*emplace-deref*(*outer*());
[🔗](#lib:get-inner,join_with_view::iterator)
`constexpr auto& get-inner();
`
[7](#iterator-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7520)
*Effects*: Equivalent to:if constexpr (*ref-is-glvalue*)return *as-lvalue*(**outer*());elsereturn **parent_*->*inner_*;
[🔗](#lib:satisfy,join_with_view::iterator)
`constexpr void satisfy();
`
[8](#iterator-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7537)
*Effects*: Equivalent to:while (true) {if (*inner_it_*.index() == 0) {if (std::get<0>(*inner_it_*) != ranges::end(*parent_*->*pattern_*))break; *inner_it_*.template emplace<1>(ranges::begin(*update-inner*())); } else {if (std::get<1>(*inner_it_*) != ranges::end(*get-inner*()))break; if (++*outer*() == ranges::end(*parent_*->*base_*)) {if constexpr (*ref-is-glvalue*)*inner_it_*.template emplace<0>(); break; }*inner_it_*.template emplace<0>(ranges::begin(*parent_*->*pattern_*)); }}
[*Note [1](#iterator-note-1)*:
join_with_view iterators use the *satisfy* function
to skip over empty inner ranges[.](#iterator-8.sentence-2)
— *end note*]
[🔗](#lib:join_with_view::iterator,constructor)
`constexpr iterator(Parent& parent, OuterIter outer)
requires [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>;
constexpr explicit iterator(Parent& parent)
requires (![forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base>);
`
[9](#iterator-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7574)
*Effects*: Initializes *parent_* with addressof(parent)[.](#iterator-9.sentence-1)
For the first overload, also initializes*outer_it_* with std::move(outer)[.](#iterator-9.sentence-2)
Then, equivalent to:if (*outer*() != ranges::end(*parent_*->*base_*)) {*inner_it_*.template emplace<1>(ranges::begin(*update-inner*())); *satisfy*();}
[🔗](#lib:join_with_view::iterator,constructor_)
`constexpr iterator(iterator<!Const> i)
requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<V>, OuterIter> &&
[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<InnerRng>, InnerIter> &&
[convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<iterator_t<Pattern>, PatternIter>;
`
[10](#iterator-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7597)
*Effects*: Initializes *outer_it_* withstd::move(i.*outer_it_*) and*parent_* with i.*parent_*[.](#iterator-10.sentence-1)
Then, equivalent to:if (i.*inner_it_*.index() == 0)*inner_it_*.template emplace<0>(std::get<0>(std::move(i.*inner_it_*)));else*inner_it_*.template emplace<1>(std::get<1>(std::move(i.*inner_it_*)));
[11](#iterator-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7610)
[*Note [2](#iterator-note-2)*:
Const can only be true when *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")[.](#iterator-11.sentence-1)
— *end note*]
[🔗](#lib:operator--,join_with_view::iterator)
`constexpr decltype(auto) operator*() const;
`
[12](#iterator-12)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7623)
*Effects*: Equivalent to:using reference = common_reference_t<iter_reference_t<*InnerIter*>, iter_reference_t<*PatternIter*>>;return visit([](auto& it) -> reference { return *it; }, *inner_it_*);
[🔗](#lib:operator++,join_with_view::iterator)
`constexpr iterator& operator++();
`
[13](#iterator-13)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7639)
*Effects*: Equivalent to:visit([](auto& it){ ++it; }, *inner_it_*);*satisfy*();return *this;
[🔗](#lib:operator++,join_with_view::iterator_)
`constexpr void operator++(int);
`
[14](#iterator-14)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7655)
*Effects*: Equivalent to ++*this[.](#iterator-14.sentence-1)
[🔗](#lib:operator++,join_with_view::iterator__)
`constexpr iterator operator++(int)
requires ref-is-glvalue && [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11Concept forward_­iterator[iterator.concept.forward]")<OuterIter> && [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11Concept forward_­iterator[iterator.concept.forward]")<InnerIter>;
`
[15](#iterator-15)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7667)
*Effects*: Equivalent to:*iterator* tmp = *this;++*this;return tmp;
[🔗](#lib:operator--,join_with_view::iterator_)
`constexpr iterator& operator--()
requires ref-is-glvalue && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base> &&
[bidirectional-common](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<InnerBase> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<PatternBase>;
`
[16](#iterator-16)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7685)
*Effects*: Equivalent to:if (*outer_it_* == ranges::end(*parent_*->*base_*)) {auto&& inner = *--*outer_it_*; *inner_it_*.template emplace<1>(ranges::end(inner));}while (true) {if (*inner_it_*.index() == 0) {auto& it = std::get<0>(*inner_it_*); if (it == ranges::begin(*parent_*->*pattern_*)) {auto&& inner = *--*outer_it_*; *inner_it_*.template emplace<1>(ranges::end(inner)); } else {break; }} else {auto& it = std::get<1>(*inner_it_*); auto&& inner = **outer_it_*; if (it == ranges::begin(inner)) {*inner_it_*.template emplace<0>(ranges::end(*parent_*->*pattern_*)); } else {break; }}} visit([](auto& it){ --it; }, *inner_it_*);return *this;
[🔗](#lib:operator--,join_with_view::iterator__)
`constexpr iterator operator--(int)
requires ref-is-glvalue && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6Other range refinements[range.refinements]")<Base> &&
[bidirectional-common](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<InnerBase> && [bidirectional-common](#concept:bidirectional-common "25.7.15.2Class template join_­with_­view[range.join.with.view]")<PatternBase>;
`
[17](#iterator-17)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7726)
*Effects*: Equivalent to:*iterator* tmp = *this;--*this;return tmp;
[🔗](#lib:operator==,join_with_view::iterator)
`friend constexpr bool operator==(const iterator& x, const iterator& y)
requires ref-is-glvalue && [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]")<Base> &&
[equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4Concept equality_­comparable[concept.equalitycomparable]")<InnerIter>;
`
[18](#iterator-18)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7744)
*Effects*: Equivalent to:return x.*outer_it_* == y.*outer_it_* && x.*inner_it_* == y.*inner_it_*;
#### [25.7.15.4](#sentinel) Class template join_with_view::*sentinel* [[range.join.with.sentinel]](range.join.with.sentinel)
[🔗](#lib:join_with_view::sentinel)
namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6Other range refinements[range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5Views[range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6Other range refinements[range.refinements]")<range_reference_t<V>>&& [view](range.view#concept:view "25.4.5Views[range.view]")<Pattern> && [*concatable*](range.concat.view#concept:concatable "25.7.18.2Class template concat_­view[range.concat.view]")<range_reference_t<V>, Pattern>template<bool Const>class join_with_view<V, Pattern>::*sentinel* {using *Parent* = *maybe-const*<Const, join_with_view>; // *exposition only*using *Base* = *maybe-const*<Const, V>; // *exposition only* sentinel_t<*Base*> *end_* = sentinel_t<*Base*>(); // *exposition only*constexpr explicit *sentinel*(*Parent*& parent); // *exposition only*public:*sentinel*() = default; constexpr *sentinel*(*sentinel*<!Const> s)requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<*Base*>>; template<bool OtherConst>requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<sentinel_t<*Base*>, iterator_t<*maybe-const*<OtherConst, V>>>friend constexpr bool operator==(const *iterator*<OtherConst>& x, const *sentinel*& y); };}
[🔗](#lib:join_with_view::sentinel,constructor)
`constexpr explicit sentinel(Parent& parent);
`
[1](#sentinel-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7786)
*Effects*: Initializes *end_* with ranges::end(parent.*base_*)[.](#sentinel-1.sentence-1)
[🔗](#lib:join_with_view::sentinel,constructor_)
`constexpr sentinel(sentinel<!Const> s)
requires Const && [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<sentinel_t<V>, sentinel_t<Base>>;
`
[2](#sentinel-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7798)
*Effects*: Initializes *end_* with std::move(s.*end_*)[.](#sentinel-2.sentence-1)
[🔗](#lib:operator==,join_with_view::sentinel)
`template<bool OtherConst>
requires [sentinel_for](iterator.concept.sentinel#concept:sentinel_for "24.3.4.7Concept sentinel_­for[iterator.concept.sentinel]")<sentinel_t<Base>, iterator_t<maybe-const<OtherConst, V>>>
friend constexpr bool operator==(const iterator<OtherConst>& x, const sentinel& y);
`
[3](#sentinel-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7811)
*Effects*: Equivalent to: return x.*outer*() == y.*end_*;