[range.join.with.iterator]

# 25 Ranges library [[ranges]](./#ranges)

## 25.7 Range adaptors [[range.adaptors]](range.adaptors#range.join.with.iterator)

### 25.7.15 Join with view [[range.join.with]](range.join.with#iterator)

#### 25.7.15.3 Class template join_with_view​::​*iterator* [range.join.with.iterator]

[ð](#lib:join_with_view::iterator)

namespace std::ranges {template<[input_range](range.refinements#concept:input_range "25.4.6 Other range refinements [range.refinements]") V, [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]") Pattern>requires [view](range.view#concept:view "25.4.5 Views [range.view]")<V> && [input_range](range.refinements#concept:input_range "25.4.6 Other range refinements [range.refinements]")<range_reference_t<V>>&& [view](range.view#concept:view "25.4.5 Views [range.view]")<Pattern> && [*concatable*](range.concat.view#concept:concatable "25.7.18.2 Class 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.6 Other 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.6 Other range refinements [range.refinements]")<*Base*>; // *exposition only*constexpr explicit *iterator*(*Parent*& parent)requires (![forward_range](range.refinements#concept:forward_range "25.4.6 Other 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.4 Concept convertible_­to [concept.convertible]")<iterator_t<V>, *OuterIter*> &&[convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]")<iterator_t<*InnerRng*>, *InnerIter*> &&[convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept 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.11 Concept forward_­iterator [iterator.concept.forward]")<*OuterIter*> &&[forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11 Concept forward_­iterator [iterator.concept.forward]")<*InnerIter*>; constexpr *iterator*& operator--()requires *ref-is-glvalue* && [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]")<*Base*> &&[*bidirectional-common*](range.join.with.view#concept:bidirectional-common "25.7.15.2 Class template join_­with_­view [range.join.with.view]")<*InnerBase*> && [*bidirectional-common*](range.join.with.view#concept:bidirectional-common "25.7.15.2 Class 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.6 Other range refinements [range.refinements]")<*Base*> &&[*bidirectional-common*](range.join.with.view#concept:bidirectional-common "25.7.15.2 Class template join_­with_­view [range.join.with.view]")<*InnerBase*> && [*bidirectional-common*](range.join.with.view#concept:bidirectional-common "25.7.15.2 Class 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.6 Other range refinements [range.refinements]")<*Base*> &&[equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept 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.4 Concept indirectly_­swappable [alg.req.ind.swap]")<*InnerIter*, *PatternIter*> { visit(ranges::iter_swap, x.*inner_it_*, y.*inner_it_*); }};}

[1](#1)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7414)

*iterator*​::​iterator_concept is defined as follows:

- [(1.1)](#1.1)

  If *ref-is-glvalue* is true,*Base* models [bidirectional_range](range.refinements#concept:bidirectional_range "25.4.6 Other range refinements [range.refinements]"), and*InnerBase* and *PatternBase* each model [*bidirectional-common*](range.join.with.view#concept:bidirectional-common "25.7.15.2 Class template join_­with_­view [range.join.with.view]"),
then iterator_concept denotes bidirectional_iterator_tag[.](#1.1.sentence-1)

- [(1.2)](#1.2)

  Otherwise, if *ref-is-glvalue* is true and*Base* and *InnerBase* each model [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]"),
then iterator_concept denotes forward_iterator_tag[.](#1.2.sentence-1)

- [(1.3)](#1.3)

  Otherwise, iterator_concept denotes input_iterator_tag[.](#1.3.sentence-1)

[2](#2)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7431)

The member [*typedef-name*](dcl.typedef#nt:typedef-name "9.2.4 The 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.6 Other range refinements [range.refinements]")[.](#2.sentence-1)

In that case,*iterator*​::​iterator_category is defined as follows:

- [(2.1)](#2.1)

  Let *OUTERC* denoteiterator_traits<*OuterIter*>​::​iterator_category,
let *INNERC* denoteiterator_traits<*InnerIter*>​::​iterator_category, and
let *PATTERNC* denoteiterator_traits<*PatternIter*>​::​iterator_category[.](#2.1.sentence-1)

- [(2.2)](#2.2)

  Ifis_reference_v<common_reference_t<iter_reference_t<*InnerIter*>,
 iter_reference_t<*PatternIter*>>> is false,iterator_category denotes input_iterator_tag[.](#2.2.sentence-1)

- [(2.3)](#2.3)

  Otherwise,
if *OUTERC*, *INNERC*, and *PATTERNC* each model [derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_­from [concept.derived]")<bidirectional_iterator_tag> and *InnerBase* and *PatternBase* each model [common_range](range.refinements#concept:common_range "25.4.6 Other range refinements [range.refinements]"),iterator_category denotes bidirectional_iterator_tag[.](#2.3.sentence-1)

- [(2.4)](#2.4)

  Otherwise,
if *OUTERC*, *INNERC*, and *PATTERNC* each model [derived_from](concept.derived#concept:derived_from "18.4.3 Concept derived_­from [concept.derived]")<forward_iterator_tag>,iterator_category denotes forward_iterator_tag[.](#2.4.sentence-1)

- [(2.5)](#2.5)

  Otherwise, iterator_category denotes input_iterator_tag[.](#2.5.sentence-1)

[3](#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](#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](#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.6 Other range refinements [range.refinements]");
otherwise, **parent_*->*outer_it_*[.](#5.sentence-1)

[ð](#lib:update-inner,join_with_view::iterator)

`constexpr auto& update-inner();
`

[6](#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](#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](#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](#note-1)*:

join_with_view iterators use the *satisfy* function
to skip over empty inner ranges[.](#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.6 Other range refinements [range.refinements]")<Base>;
constexpr explicit iterator(Parent& parent)
  requires (![forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")<Base>);
`

[9](#9)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7574)

*Effects*: Initializes *parent_* with addressof(parent)[.](#9.sentence-1)

For the first overload, also initializes*outer_it_* with std​::​move(outer)[.](#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.4 Concept convertible_­to [concept.convertible]")<iterator_t<V>, OuterIter> &&
             [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]")<iterator_t<InnerRng>, InnerIter> &&
             [convertible_to](concept.convertible#concept:convertible_to "18.4.4 Concept convertible_­to [concept.convertible]")<iterator_t<Pattern>, PatternIter>;
`

[10](#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_*[.](#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](#11)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7610)

[*Note [2](#note-2)*:

Const can only be true when *Base* models [forward_range](range.refinements#concept:forward_range "25.4.6 Other range refinements [range.refinements]")[.](#11.sentence-1)

â *end note*]

[ð](#lib:operator--,join_with_view::iterator)

`constexpr decltype(auto) operator*() const;
`

[12](#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](#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](#14)

[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/ranges.tex#L7655)

*Effects*: Equivalent to ++*this[.](#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.11 Concept forward_­iterator [iterator.concept.forward]")<OuterIter> && [forward_iterator](iterator.concept.forward#concept:forward_iterator "24.3.4.11 Concept forward_­iterator [iterator.concept.forward]")<InnerIter>;
`

[15](#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.6 Other range refinements [range.refinements]")<Base> &&
           [bidirectional-common](range.join.with.view#concept:bidirectional-common "25.7.15.2 Class template join_­with_­view [range.join.with.view]")<InnerBase> && [bidirectional-common](range.join.with.view#concept:bidirectional-common "25.7.15.2 Class template join_­with_­view [range.join.with.view]")<PatternBase>;
`

[16](#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.6 Other range refinements [range.refinements]")<Base> &&
           [bidirectional-common](range.join.with.view#concept:bidirectional-common "25.7.15.2 Class template join_­with_­view [range.join.with.view]")<InnerBase> && [bidirectional-common](range.join.with.view#concept:bidirectional-common "25.7.15.2 Class template join_­with_­view [range.join.with.view]")<PatternBase>;
`

[17](#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.6 Other range refinements [range.refinements]")<Base> &&
           [equality_comparable](concept.equalitycomparable#concept:equality_comparable "18.5.4 Concept equality_­comparable [concept.equalitycomparable]")<InnerIter>;
`

[18](#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_*;
