24 Ranges library [ranges]

24.7 Range adaptors [range.adaptors]

24.7.11 Join view [range.join]

24.7.11.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>> && (is_reference_v<range_reference_t<V>> || view<range_value_t<V>>) template<bool Const> struct join_view<V>::iterator { private: using Parent = // exposition only conditional_t<Const, const join_view, join_view>; using Base = conditional_t<Const, const V, V>; // exposition only static constexpr bool ref-is-glvalue = // exposition only is_reference_v<range_reference_t<Base>>; iterator_t<Base> outer_ = iterator_t<Base>(); // exposition only iterator_t<range_reference_t<Base>> inner_ = // exposition only iterator_t<range_reference_t<Base>>(); Parent* parent_ = nullptr; // exposition only constexpr void satisfy(); // exposition only public: using iterator_concept = see below; using iterator_category = see below; using value_type = range_value_t<range_reference_t<Base>>; using difference_type = see below; iterator() = default; constexpr iterator(Parent& parent, iterator_t<Base> outer); constexpr iterator(iterator<!Const> i) requires Const && convertible_­to<iterator_t<V>, iterator_t<Base>> && convertible_­to<iterator_t<InnerRng>, iterator_t<range_reference_t<Base>>>; constexpr decltype(auto) operator*() const { return *inner_; } constexpr iterator_t<Base> operator->() const requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>; 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 && equality_­comparable<iterator_t<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_))); }; }
iterator​::​iterator_­concept is defined as follows:
  • If ref-is-glvalue is true and Base and range_­reference_­t<Base> each model bidirectional_­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.
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 ref-is-glvalue is true and OUTERC and INNERC each model derived_­from<bidirectional_­iterator_­tag>, iterator_­category denotes bidirectional_­iterator_­tag.
  • Otherwise, if ref-is-glvalue is true and OUTERC and INNERC each model derived_­from<forward_­iterator_­tag>, iterator_­category denotes forward_­iterator_­tag.
  • Otherwise, if OUTERC and INNERC each model derived_­from<input_­iterator_­tag>, iterator_­category denotes input_­iterator_­tag.
  • Otherwise, iterator_­category denotes output_­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 void satisfy(); // exposition only
Effects: Equivalent to: auto update_inner = [this](range_reference_t<Base> x) -> auto& { if constexpr (ref-is-glvalue) // x is a reference return x; else return (parent_->inner_ = views::all(std::move(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_ = iterator_t<range_reference_t<Base>>();
constexpr iterator(Parent& parent, iterator_t<Base> outer);
Effects: Initializes outer_­ with std​::​move(outer) and parent_­ with addressof(parent); then calls satisfy().
constexpr iterator(iterator<!Const> i) requires Const && convertible_­to<iterator_t<V>, iterator_t<Base>> && convertible_­to<iterator_t<InnerRng>, iterator_t<range_reference_t<Base>>>;
Effects: Initializes outer_­ with std​::​move(i.outer_­), inner_­ with std​::​move(i.inner_­), and parent_­ with i.parent_­.
constexpr iterator_t<Base> operator->() const requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>;
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: auto&& inner_rng = inner-range; if (++inner_ == ranges::end(inner_rng)) { ++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(*--outer_); while (inner_ == ranges::begin(*outer_)) inner_ = ranges::end(*--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 && equality_comparable<iterator_t<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_­)));
Effects: Equivalent to: return ranges​::​iter_­swap(x.inner_­, y.inner_­);