24 Ranges library [ranges]

24.7 Range adaptors [range.adaptors]

24.7.10 Join view [range.join]

24.7.10.3 Class template join_­view​::​iterator [range.join.iterator]

namespace std::ranges {
template<class 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<V> 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>>;

    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>>;

    constexpr iterator operator--(int)
      requires ref_is_glvalue && bidirectional_range<Base> &&
               bidirectional_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,
    • If Base and range_­reference_­t<Base> each model bidirectional_­range, then iterator_­concept denotes bidirectional_­iterator_­tag.
    • Otherwise, if 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,
    • If OUTERC and INNERC each model derived_­from<bidirectional_­iterator_­tag>, 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 void satisfy(); // exposition only
Effects: Equivalent to:
auto update_inner = [this](range_reference_t<Base> x) -> decltype(auto) {
  if constexpr (ref_is_glvalue) // x is a reference
    return (x);                 // (x) is an lvalue
  else
    return (parent_->inner_ = views::all(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<V> outer)
Effects: Initializes outer_­ with 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>>;
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>>;
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>>;
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_­);