25 Ranges library [ranges]

25.7 Range adaptors [range.adaptors]

25.7.14 Join view [range.join]

25.7.14.3 Class template join_view​::​iterator [range.join.iterator]

namespace std::ranges { template<input_range V> requires view<V> && input_range<range_reference_t<V>> template<bool Const> struct join_view<V>::iterator { private: using Parent = maybe-const<Const, join_view>; // exposition only using Base = maybe-const<Const, V>; // exposition only using OuterIter = iterator_t<Base>; // exposition only using InnerIter = iterator_t<range_reference_t<Base>>; // exposition only static constexpr bool ref-is-glvalue = // exposition only is_reference_v<range_reference_t<Base>>; OuterIter outer_ = OuterIter(); // exposition only, present only // if Base models forward_range optional<InnerIter> inner_; // exposition only Parent* parent_ = nullptr; // exposition only constexpr void satisfy(); // exposition only constexpr OuterIter& outer(); // exposition only constexpr const OuterIter& outer() const; // exposition only constexpr iterator(Parent& parent, OuterIter outer) requires forward_range<Base>; // exposition only constexpr explicit iterator(Parent& parent) requires (!forward_range<Base>); // exposition only public: using iterator_concept = see below; using iterator_category = see below; // not always present using value_type = range_value_t<range_reference_t<Base>>; using difference_type = see below; iterator() = default; constexpr iterator(iterator<!Const> i) requires Const && convertible_to<iterator_t<V>, OuterIter> && convertible_to<iterator_t<InnerRng>, InnerIter>; constexpr decltype(auto) operator*() const { return **inner_; } constexpr InnerIter operator->() const requires has-arrow<InnerIter> && copyable<InnerIter>; constexpr iterator& operator++(); constexpr void operator++(int); constexpr iterator operator++(int) requires ref-is-glvalue && forward_range<Base> && forward_range<range_reference_t<Base>>; constexpr iterator& operator--() requires ref-is-glvalue && bidirectional_range<Base> && bidirectional_range<range_reference_t<Base>> && common_range<range_reference_t<Base>>; constexpr iterator operator--(int) requires ref-is-glvalue && bidirectional_range<Base> && bidirectional_range<range_reference_t<Base>> && common_range<range_reference_t<Base>>; friend constexpr bool operator==(const iterator& x, const iterator& y) requires ref-is-glvalue && forward_range<Base> && equality_comparable<iterator_t<range_reference_t<Base>>>; friend constexpr decltype(auto) iter_move(const iterator& i) noexcept(noexcept(ranges::iter_move(*i.inner_))) { return ranges::iter_move(*i.inner_); } friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_))) requires indirectly_swappable<InnerIter>; }; }
iterator​::​iterator_concept is defined as follows:
  • If ref-is-glvalue is true, Base models bidirectional_range, and range_reference_t<Base> models both bidirectional_range and common_range, then iterator_concept denotes bidirectional_iterator_tag.
  • Otherwise, if ref-is-glvalue is true and Base and range_reference_t<Base> each model forward_range, then iterator_concept denotes forward_iterator_tag.
  • Otherwise, iterator_concept denotes input_iterator_tag.
The member typedef-name iterator_category is defined if and only if ref-is-glvalue is true, Base models forward_range, and range_reference_t<Base> models forward_range.
In that case, iterator​::​iterator_category is defined as follows:
  • Let OUTERC denote iterator_traits<iterator_t<Base>>​::​iterator_category, and let INNERC denote iterator_traits<iterator_t<range_reference_t<Base>>>​::​iterator_category.
  • If OUTERC and INNERC each model derived_from<bidirectional_iterator_tag> and range_reference_t<Base> models common_range, iterator_category denotes bidirectional_iterator_tag.
  • Otherwise, if OUTERC and INNERC each model derived_from<forward_iterator_tag>, iterator_category denotes forward_iterator_tag.
  • Otherwise, iterator_category denotes input_iterator_tag.
iterator​::​difference_type denotes the type: common_type_t< range_difference_t<Base>, range_difference_t<range_reference_t<Base>>>
join_view iterators use the satisfy function to skip over empty inner ranges.
constexpr OuterIter& outer(); constexpr const OuterIter& outer() const;
Returns: outer_ if Base models forward_range; otherwise, *parent_->outer_.
constexpr void satisfy();
Effects: Equivalent to: auto update_inner = [this](const iterator_t<Base>& x) -> auto&& { if constexpr (ref-is-glvalue) // *x is a reference return *x; else return parent_->inner_.emplace-deref(x); }; for (; outer() != ranges::end(parent_->base_); ++outer()) { auto&& inner = update_inner(outer()); inner_ = ranges::begin(inner); if (*inner_ != ranges::end(inner)) return; } if constexpr (ref-is-glvalue) inner_.reset();
constexpr iterator(Parent& parent, OuterIter outer) requires forward_range<Base>;
Effects: Initializes outer_ with std​::​move(outer) and parent_ with addressof(parent); then calls satisfy().
constexpr explicit iterator(Parent& parent) requires (!forward_range<Base>);
Effects: Initializes parent_ with addressof(parent); then calls satisfy().
constexpr iterator(iterator<!Const> i) requires Const && convertible_to<iterator_t<V>, OuterIter> && convertible_to<iterator_t<InnerRng>, InnerIter>;
Effects: Initializes outer_ with std​::​move(i.outer_), inner_ with std​::​move(i.inner_), and parent_ with i.parent_.
[Note 1: 
Const can only be true when Base models forward_range.
— end note]
constexpr InnerIter operator->() const requires has-arrow<InnerIter> && copyable<InnerIter>;
Effects: Equivalent to: return *inner_;
constexpr iterator& operator++();
Let inner-range be:
  • If ref-is-glvalue is true, *outer().
  • Otherwise, *parent_->inner_.
Effects: Equivalent to: if (++*inner_ == ranges::end(as-lvalue(inner-range))) { ++outer(); satisfy(); } return *this;
constexpr void operator++(int);
Effects: Equivalent to: ++*this.
constexpr iterator operator++(int) requires ref-is-glvalue && forward_range<Base> && forward_range<range_reference_t<Base>>;
Effects: Equivalent to: auto tmp = *this; ++*this; return tmp;
constexpr iterator& operator--() requires ref-is-glvalue && bidirectional_range<Base> && bidirectional_range<range_reference_t<Base>> && common_range<range_reference_t<Base>>;
Effects: Equivalent to: if (outer_ == ranges::end(parent_->base_)) inner_ = ranges::end(as-lvalue(*--outer_)); while (*inner_ == ranges::begin(as-lvalue(*outer_))) *inner_ = ranges::end(as-lvalue(*--outer_)); --*inner_; return *this;
constexpr iterator operator--(int) requires ref-is-glvalue && bidirectional_range<Base> && bidirectional_range<range_reference_t<Base>> && common_range<range_reference_t<Base>>;
Effects: Equivalent to: auto tmp = *this; --*this; return tmp;
friend constexpr bool operator==(const iterator& x, const iterator& y) requires ref-is-glvalue && forward_range<Base> && equality_comparable<iterator_t<range_reference_t<Base>>>;
Effects: Equivalent to: return x.outer_ == y.outer_ && x.inner_ == y.inner_;
friend constexpr void iter_swap(const iterator& x, const iterator& y) noexcept(noexcept(ranges::iter_swap(*x.inner_, *y.inner_))) requires indirectly_swappable<InnerIter>;
Effects: Equivalent to: return ranges​::​iter_swap(*x.inner_, *y.inner_);