24 Ranges library [ranges]

24.7 Range adaptors [range.adaptors]

24.7.7 Join view [range.join]

24.7.7.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<iter_reference_t<iterator_t<Base>>>;

    iterator_t<Base> outer_ = iterator_t<Base>();               // exposition only
    iterator_t<iter_reference_t<iterator_t<Base>>> inner_ =     // exposition only
      iterator_t<iter_reference_t<iterator_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        =
      iter_value_t<iterator_t<iter_reference_t<iterator_t<Base>>>>;
    using difference_type   = see below;

    iterator() = default;
    constexpr iterator(Parent& parent, iterator_t<V> outer);
    constexpr iterator(iterator<!Const> i)
      requires Const &&
               ConvertibleTo<iterator_t<V>, iterator_t<Base>> &&
               ConvertibleTo<iterator_t<InnerRng>,
                             iterator_t<iter_reference_t<iterator_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 && ForwardRange<Base> &&
               ForwardRange<iter_reference_t<iterator_t<Base>>>;

    constexpr iterator& operator--()
      requires ref_is_glvalue && BidirectionalRange<Base> &&
               BidirectionalRange<iter_reference_t<iterator_t<Base>>>;

    constexpr iterator operator--(int)
      requires ref_is_glvalue && BidirectionalRange<Base> &&
               BidirectionalRange<iter_reference_t<iterator_t<Base>>>;

    friend constexpr bool operator==(const iterator& x, const iterator& y)
      requires ref_is_glvalue && EqualityComparable<iterator_t<Base>> &&
               EqualityComparable<iterator_t<iter_reference_t<iterator_t<Base>>>>;

    friend constexpr bool operator!=(const iterator& x, const iterator& y)
      requires ref_is_glvalue && EqualityComparable<iterator_t<Base>> &&
               EqualityComparable<iterator_t<iter_reference_t<iterator_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 iter_­reference_­t<iterator_­t<Base>> each model BidirectionalRange, then iterator_­concept denotes bidirectional_­iterator_­tag.
    • Otherwise, if Base and iter_­reference_­t<iterator_­t<Base>> each model ForwardRange, 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<iter_­reference_­t<iterator_­t<Base>>>>::iterator_­category.
  • If ref_­is_­glvalue is true,
    • If OUTERC and INNERC each model DerivedFrom<bidirectional_­iterator_­tag>, iterator_­category denotes bidirectional_­iterator_­tag.
    • Otherwise, if OUTERC and INNERC each model DerivedFrom<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<
  iter_difference_t<iterator_t<Base>>,
  iter_difference_t<iterator_t<iter_reference_t<iterator_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](iter_reference_t<iterator_t<Base>> x) -> decltype(auto) {
  if constexpr (ref_is_glvalue) // x is a reference
    return (x);                 // (x) is an lvalue
  else
    return (parent_->inner_ = view::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<iter_reference_t<iterator_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 && ConvertibleTo<iterator_t<V>, iterator_t<Base>> && ConvertibleTo<iterator_t<InnerRng>, iterator_t<iter_reference_t<iterator_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 && ForwardRange<Base> && ForwardRange<iter_reference_t<iterator_t<Base>>>;
Effects: Equivalent to:
auto tmp = *this;
++*this;
return tmp;
constexpr iterator& operator--() requires ref_is_glvalue && BidirectionalRange<Base> && BidirectionalRange<iter_reference_t<iterator_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 && BidirectionalRange<Base> && BidirectionalRange<iter_reference_t<iterator_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 && EqualityComparable<iterator_t<Base>> && EqualityComparable<iterator_t<iter_reference_t<iterator_t<Base>>>>;
Effects: Equivalent to: return x.outer_­ == y.outer_­ && x.inner_­ == y.inner_­;
friend constexpr bool operator!=(const iterator& x, const iterator& y) requires ref_is_glvalue && EqualityComparable<iterator_t<Base>> && EqualityComparable<iterator_t<iter_reference_t<iterator_t<Base>>>>;
Effects: Equivalent to: return !(x == y);
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_­);