9 Iterators library [iterators]

9.7 Iterator adaptors [iterators.predef]

9.7.3 Move iterators and sentinels [iterators.move]

9.7.3.1 Class template move_iterator [move.iterator]

Class template move_iterator is an iterator adaptor with the same behavior as the underlying iterator except that its indirection operator implicitly converts the value returned by the underlying iterator's indirection operator to an rvalue of the value type. Some generic algorithms can be called with move iterators to replace copying with moving.

Example:

list<string> s;
// populate the list s
vector<string> v1(s.begin(), s.end());          // copies strings into v1
vector<string> v2(make_move_iterator(s.begin()),
                  make_move_iterator(s.end())); // moves strings into v2

 — end example ]

namespace std { namespace experimental { namespace ranges { inline namespace v1 {
  template <InputIterator I>
  class move_iterator {
  public:
    using iterator_type     = I;
    using difference_type   = difference_type_t<I>;
    using value_type        = value_type_t<I>;
    using iterator_category = input_iterator_tag;
    using reference         = rvalue_reference_t<I>;

    constexpr move_iterator();
    explicit constexpr move_iterator(I i);
    constexpr move_iterator(const move_iterator<ConvertibleTo<I>>& i);
    constexpr move_iterator& operator=(const move_iterator<ConvertibleTo<I>>& i);

    constexpr I base() const;
    constexpr reference operator*() const;

    constexpr move_iterator& operator++();
    constexpr void operator++(int);
    constexpr move_iterator operator++(int)
      requires ForwardIterator<I>;
    constexpr move_iterator& operator--()
      requires BidirectionalIterator<I>;
    constexpr move_iterator operator--(int)
      requires BidirectionalIterator<I>;

    constexpr move_iterator operator+(difference_type n) const
      requires RandomAccessIterator<I>;
    constexpr move_iterator& operator+=(difference_type n)
      requires RandomAccessIterator<I>;
    constexpr move_iterator operator-(difference_type n) const
      requires RandomAccessIterator<I>;
    constexpr move_iterator& operator-=(difference_type n)
      requires RandomAccessIterator<I>;
    constexpr reference operator[](difference_type n) const
      requires RandomAccessIterator<I>;

    friend constexpr rvalue_reference_t<I> iter_move(const move_iterator& i)
      noexcept(see below);
    template <IndirectlySwappable<I> I2>
      friend constexpr void iter_swap(const move_iterator& x, const move_iterator<I2>& y)
        noexcept(see below);

  private:
    I current; // exposition only
  };

  template <class I1, class I2>
      requires EqualityComparableWith<I1, I2>
    constexpr bool operator==(
      const move_iterator<I1>& x, const move_iterator<I2>& y);
  template <class I1, class I2>
      requires EqualityComparableWith<I1, I2>
    constexpr bool operator!=(
      const move_iterator<I1>& x, const move_iterator<I2>& y);
  template <class I1, class I2>
      requires StrictTotallyOrderedWith<I1, I2>
    constexpr bool operator<(
      const move_iterator<I1>& x, const move_iterator<I2>& y);
  template <class I1, class I2>
      requires StrictTotallyOrderedWith<I1, I2>
    constexpr bool operator<=(
      const move_iterator<I1>& x, const move_iterator<I2>& y);
  template <class I1, class I2>
      requires StrictTotallyOrderedWith<I1, I2>
    constexpr bool operator>(
      const move_iterator<I1>& x, const move_iterator<I2>& y);
  template <class I1, class I2>
      requires StrictTotallyOrderedWith<I1, I2>
    constexpr bool operator>=(
      const move_iterator<I1>& x, const move_iterator<I2>& y);

  template <class I1, class I2>
      requires SizedSentinel<I1, I2>
    constexpr difference_type_t<I2> operator-(
      const move_iterator<I1>& x,
      const move_iterator<I2>& y);
  template <RandomAccessIterator I>
    constexpr move_iterator<I> operator+(
      difference_type_t<I> n,
      const move_iterator<I>& x);
  template <InputIterator I>
    constexpr move_iterator<I> make_move_iterator(I i);
}}}}

Note: move_iterator does not provide an operator-> because the class member access expression i->m may have different semantics than the expression (*i).m when the expression *i is an rvalue. — end note ]

9.7.3.2 move_iterator operations [move.iter.ops]

9.7.3.2.1 move_iterator constructors [move.iter.op.const]

constexpr move_iterator();

Effects: Constructs a move_iterator, value-initializing current. Iterator operations applied to the resulting iterator have defined behavior if and only if the corresponding operations are defined on a value-initialized iterator of type I.

explicit constexpr move_iterator(I i);

Effects: Constructs a move_iterator, initializing current with i.

constexpr move_iterator(const move_iterator<ConvertibleTo<I>>& i);

Effects: Constructs a move_iterator, initializing current with i.current.

9.7.3.2.2 move_iterator::operator= [move.iter.op=]

constexpr move_iterator& operator=(const move_iterator<ConvertibleTo<I>>& i);

Effects: Assigns i.current to current.

9.7.3.2.3 move_iterator conversion [move.iter.op.conv]

constexpr I base() const;

Returns: current.

9.7.3.2.4 move_iterator::operator* [move.iter.op.star]

constexpr reference operator*() const;

Effects: Equivalent to: return iter_move(current);

9.7.3.2.5 move_iterator::operator++ [move.iter.op.incr]

constexpr move_iterator& operator++();

Effects: Equivalent to ++current.

Returns: *this.

constexpr void operator++(int);

Effects: Equivalent to ++current.

constexpr move_iterator operator++(int) requires ForwardIterator<I>;

Effects: Equivalent to:

move_iterator tmp = *this;
++current;
return tmp;

9.7.3.2.6 move_iterator::operator-- [move.iter.op.decr]

constexpr move_iterator& operator--() requires BidirectionalIterator<I>;

Effects: Equivalent to --current.

Returns: *this.

constexpr move_iterator operator--(int) requires BidirectionalIterator<I>;

Effects: Equivalent to:

move_iterator tmp = *this;
--current;
return tmp;

9.7.3.2.7 move_iterator::operator+ [move.iter.op.+]

constexpr move_iterator operator+(difference_type n) const requires RandomAccessIterator<I>;

Effects: Equivalent to: return move_iterator(current + n);

9.7.3.2.8 move_iterator::operator+= [move.iter.op.+=]

constexpr move_iterator& operator+=(difference_type n) requires RandomAccessIterator<I>;

Effects: Equivalent to current += n.

Returns: *this.

9.7.3.2.9 move_iterator::operator- [move.iter.op.-]

constexpr move_iterator operator-(difference_type n) const requires RandomAccessIterator<I>;

Effects: Equivalent to: return move_iterator(current - n);

9.7.3.2.10 move_iterator::operator-= [move.iter.op.-=]

constexpr move_iterator& operator-=(difference_type n) requires RandomAccessIterator<I>;

Effects: Equivalent to current -= n.

Returns: *this.

9.7.3.2.11 move_iterator::operator[] [move.iter.op.index]

constexpr reference operator[](difference_type n) const requires RandomAccessIterator<I>;

Effects: Equivalent to: return iter_move(current + n);

9.7.3.2.12 move_iterator comparisons [move.iter.op.comp]

template <class I1, class I2> requires EqualityComparableWith<I1, I2> constexpr bool operator==( const move_iterator<I1>& x, const move_iterator<I2>& y);

Effects: Equivalent to: return x.current == y.current;

template <class I1, class I2> requires EqualityComparableWith<I1, I2> constexpr bool operator!=( const move_iterator<I1>& x, const move_iterator<I2>& y);

Effects: Equivalent to: return !(x == y);

template <class I1, class I2> requires StrictTotallyOrderedWith<I1, I2> constexpr bool operator<( const move_iterator<I1>& x, const move_iterator<I2>& y);

Effects: Equivalent to: return x.current < y.current;

template <class I1, class I2> requires StrictTotallyOrderedWith<I1, I2> constexpr bool operator<=( const move_iterator<I1>& x, const move_iterator<I2>& y);

Effects: Equivalent to: return !(y < x);

template <class I1, class I2> requires StrictTotallyOrderedWith<I1, I2> constexpr bool operator>( const move_iterator<I1>& x, const move_iterator<I2>& y);

Effects: Equivalent to: return y < x;

template <class I1, class I2> requires StrictTotallyOrderedWith<I1, I2> constexpr bool operator>=( const move_iterator<I1>& x, const move_iterator<I2>& y);

Effects: Equivalent to: return !(x < y);.

9.7.3.2.13 move_iterator non-member functions [move.iter.nonmember]

template <class I1, class I2> requires SizedSentinel<I1, I2> constexpr difference_type_t<I2> operator-( const move_iterator<I1>& x, const move_iterator<I2>& y);

Effects: Equivalent to: return x.current - y.current;

template <RandomAccessIterator I> constexpr move_iterator<I> operator+( difference_type_t<I> n, const move_iterator<I>& x);

Effects: Equivalent to: return x + n;

friend constexpr rvalue_reference_t<I> iter_move(const move_iterator& i) noexcept(see below);

Effects: Equivalent to: return ranges::iter_move(i.current);

Remarks: The expression in noexcept is equivalent to:

noexcept(ranges::iter_move(i.current))

template <IndirectlySwappable<I> I2> friend constexpr void iter_swap(const move_iterator& x, const move_iterator<I2>& y) noexcept(see below);

Effects: Equivalent to: ranges::iter_swap(x.current, y.current).

Remarks: The expression in noexcept is equivalent to:

noexcept(ranges::iter_swap(x.current, y.current))

template <InputIterator I> constexpr move_iterator<I> make_move_iterator(I i);

Returns: move_iterator<I>(i).

9.7.3.3 Class template move_sentinel [move.sentinel]

Class template move_sentinel is a sentinel adaptor useful for denoting ranges together with move_iterator. When an input iterator type I and sentinel type S satisfy Sentinel<S, I>, Sentinel<move_sentinel<S>, move_iterator<I>> is satisfied as well.

Example: A move_if algorithm is easily implemented with copy_if using move_iterator and move_sentinel:

template <InputIterator I, Sentinel<I> S, WeaklyIncrementable O,
          IndirectUnaryPredicate<I> Pred>
  requires IndirectlyMovable<I, O>
void move_if(I first, S last, O out, Pred pred){
  copy_if(move_iterator<I>{first}, move_sentinel<S>{last}, out, pred);
}

 — end example ]

namespace std { namespace experimental { namespace ranges { inline namespace v1 {
  template <Semiregular S>
  class move_sentinel {
  public:
    constexpr move_sentinel();
    explicit move_sentinel(S s);
    move_sentinel(const move_sentinel<ConvertibleTo<S>>& s);
    move_sentinel& operator=(const move_sentinel<ConvertibleTo<S>>& s);

    S base() const;

  private:
    S last; // exposition only
  };

  template <class I, Sentinel<I> S>
    constexpr bool operator==(
      const move_iterator<I>& i, const move_sentinel<S>& s);
  template <class I, Sentinel<I> S>
    constexpr bool operator==(
      const move_sentinel<S>& s, const move_iterator<I>& i);
  template <class I, Sentinel<I> S>
    constexpr bool operator!=(
      const move_iterator<I>& i, const move_sentinel<S>& s);
  template <class I, Sentinel<I> S>
    constexpr bool operator!=(
      const move_sentinel<S>& s, const move_iterator<I>& i);

  template <class I, SizedSentinel<I> S>
    constexpr difference_type_t<I> operator-(
      const move_sentinel<S>& s, const move_iterator<I>& i);
  template <class I, SizedSentinel<I> S>
    constexpr difference_type_t<I> operator-(
      const move_iterator<I>& i, const move_sentinel<S>& s);

  template <Semiregular S>
    constexpr move_sentinel<S> make_move_sentinel(S s);
}}}}

9.7.3.4 move_sentinel operations [move.sent.ops]

9.7.3.4.1 move_sentinel constructors [move.sent.op.const]

constexpr move_sentinel();

Effects: Constructs a move_sentinel, value-initializing last. If is_trivially_default_constructible<S>::value is true, then this constructor is a constexpr constructor.

explicit move_sentinel(S s);

Effects: Constructs a move_sentinel, initializing last with s.

move_sentinel(const move_sentinel<ConvertibleTo<S>>& s);

Effects: Constructs a move_sentinel, initializing last with s.last.

9.7.3.4.2 move_sentinel::operator= [move.sent.op=]

move_sentinel& operator=(const move_sentinel<ConvertibleTo<S>>& s);

Effects: Assigns s.last to last.

Returns: *this.

9.7.3.4.3 move_sentinel comparisons [move.sent.op.comp]

template <class I, Sentinel<I> S> constexpr bool operator==( const move_iterator<I>& i, const move_sentinel<S>& s); template <class I, Sentinel<I> S> constexpr bool operator==( const move_sentinel<S>& s, const move_iterator<I>& i);

Effects: Equivalent to: return i.current == s.last;

template <class I, Sentinel<I> S> constexpr bool operator!=( const move_iterator<I>& i, const move_sentinel<S>& s); template <class I, Sentinel<I> S> constexpr bool operator!=( const move_sentinel<S>& s, const move_iterator<I>& i);

Effects: Equivalent to: return !(i == s);

9.7.3.4.4 move_sentinel non-member functions [move.sent.nonmember]

template <class I, SizedSentinel<I> S> constexpr difference_type_t<I> operator-( const move_sentinel<S>& s, const move_iterator<I>& i);

Effects: Equivalent to: return s.last - i.current;

template <class I, SizedSentinel<I> S> constexpr difference_type_t<I> operator-( const move_iterator<I>& i, const move_sentinel<S>& s);

Effects: Equivalent to: return i.current - s.last;

template <Semiregular S> constexpr move_sentinel<S> make_move_sentinel(S s);

Returns: move_sentinel<S>(s).