Document number: N1859=05-0119

Howard E. Hinnant
2005-08-26

Rvalue Reference Recommendations for Chapter 24

Contents

Related papers

Rvalue Reference Recommendations for Chapter 20
Rvalue Reference Recommendations for Chapter 21
Rvalue Reference Recommendations for Chapter 23
Rvalue Reference Recommendations for Chapter 25
Rvalue Reference Recommendations for Chapter 26
Rvalue Reference Recommendations for Chapter 27

Introduction

This paper recommends proposed wording with respect to the rvalue reference for the C++0X working draft. This paper restricts its scope to Chapter 24 "Iterators library" for the purpose of breaking the library work associated with the rvalue reference up into manageable chunks. This paper largely follows the lead of N1771: Impact of the rvalue reference on the Standard Library, but adds more detail as appropriate. Refer to N1771 for detailed motivation for these changes.

With the exception of this introduction, all non-proposed wording will have a background color and formatting that

looks like this, so that motivation and description is more easily distinguished from proposed wording.

In the proposed wording below, text to be inserted is formatted like this, while wording to be deleted is formatted like this.

The proposed wording in this paper:

24.2 - Header <iterator> synopsis

  template <class Container> class insert_iterator;
  template <class Container, class Iterator>
    insert_iterator<Container> inserter(Container& x, Iterator i);

  template <class Iterator> class move_iterator;

  template <class Iterator1, class Iterator2>
  bool
  operator==(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator!=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator< (const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator<=(const move_iterator<Iterator1>& x, const move_iterator<Iterator>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator> (const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator>=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  typename move_iterator<Iterator>::difference_type
  operator-(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator>
  move_iterator<Iterator>
  operator+(typename move_iterator<Iterator>::difference_type n,
            const move_iterator<Iterator>& x);

  template <class Iterator>
  move_iterator<Iterator>
  make_move_iterator(const Iterator& i);

24.4 - Predefined iterators

24.4.2 - Insert iterators

Consider the following code:

vector<unique_ptr<int> > v1, v2;
...
remove_copy(make_move_iterator(v1.begin()), make_move_iterator(v1.end()),
            back_inserter(v2), unique_ptr<int>());

In order for the above code to work, the back_insert_iterator formed by back_inserter must move assign instead of copy assign from rvalues. This is accomplished by overloading the back_insert_iterator assignment operator for both const value_type& and value_type&& parameters, with the latter performing a move assignment.

Similar additions are also needed for front_insert_iterator and insert_iterator.

24.4.2.1 - Class template back_insert_iterator

  template <class Container>
  class back_insert_iterator :
        public iterator<output_iterator_tag,void,void,void,void> {
  protected:
    Container* container;

  public:
    typedef Container container_type;
    explicit back_insert_iterator(Container& x);
    back_insert_iterator<Container>&
      operator=(typename Container::const_reference value);
    back_insert_iterator&
      operator=(typename Container::value_type&& value);

    back_insert_iterator<Container>& operator*();
    back_insert_iterator<Container>& operator++();
    back_insert_iterator<Container>  operator++(int);
  };

24.4.2.2 - back_insert_iterator operations

24.4.2.2.2 - back_insert_iterator::operator=
back_insert_iterator<Container>&
  operator=(typename Container::const_reference value);

-1- Effects: container->push_back(value);

-2- Returns: *this.


back_insert_iterator&
  operator=(typename Container::value_type&& value);

-3- Effects: container->push_back(std::move(value));

-4- Returns: *this.

24.4.2.3 - Class template front_insert_iterator

  template <class Container>
  class front_insert_iterator :
        public iterator<output_iterator_tag,void,void,void,void> {
  protected:
    Container* container;

  public:
    typedef Container container_type;
    explicit front_insert_iterator(Container& x);
    front_insert_iterator<Container>&
      operator=(typename Container::const_reference value);
    front_insert_iterator&
      operator=(typename Container::value_type&& value);

    front_insert_iterator<Container>& operator*();
    front_insert_iterator<Container>& operator++();
    front_insert_iterator<Container>  operator++(int);
  };

24.4.2.4 - front_insert_iterator operations

24.4.2.4.2 - front_insert_iterator::operator=
front_insert_iterator<Container>&
  operator=(typename Container::const_reference value);

-1- Effects: container->push_front(value);

-2- Returns: *this.


front_insert_iterator&
  operator=(typename Container::value_type&& value);

-3- Effects: container->push_front(std::move(value));

-4- Returns: *this.

24.4.2.5 - Class template insert_iterator

  template <class Container>
  class insert_iterator :
        public iterator<output_iterator_tag,void,void,void,void> {
  protected:
    Container* container;
    typename Container::iterator iter;

  public:
    typedef Container container_type;
    insert_iterator(Container& x, typename Container::iterator i);
    insert_iterator<Container>&
      operator=(typename Container::const_reference value);
    insert_iterator&
      operator=(typename Container::value_type&& value);

    insert_iterator<Container>& operator*();
    insert_iterator<Container>& operator++();
    insert_iterator<Container>& operator++(int);
  };

24.4.2.6 - insert_iterator operations

24.4.2.6.2 - insert_iterator::operator=
insert_iterator<Container>&
  operator=(typename Container::const_reference value);

-1- Effects:

  iter = container->insert(iter, value);
  ++iter;

-2- Returns: *this.


insert_iterator&
  operator=(typename Container::value_type&& value);

-3- Effects:


  iter = container->insert(iter, std::move(value));
  ++iter;

-4- Returns: *this.

24.4.3 - Class template move_iterator

24.4.3 is a new section to be inserted. The entire section is not marked in yellow in an attempt to make it more readable.

-1- Class template move_iterator is an iterator adaptor that mimics the underlying base iterator except that on dereference, the result of dereferencing the underlying iterator is implicitly cast to an rvalue reference. This can be used to transform existing generic code which assumes copy semantics, into an algorithm that moves from the source instead of copies from the source.

-2- [Example:

set<string> s;
...
vector<string> v1(s.begin(), s.end());           // strings copied into v1
vector<string> v2(make_move_iterator(s.begin()),
                  make_move_iterator(s.end()));  // strings moved into v2

-- end example]

namespace std {
  template <class Iterator>
  class move_iterator
  {
  public:
      typedef Iterator                                              iterator_type;
      typedef typename iterator_traits<Iterator>::difference_type   difference_type;
      typedef typename iterator_traits<Iterator>::pointer           pointer;
      typedef typename iterator_traits<Iterator>::value_type        value_type;
      typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
      typedef value_type&&                                          reference;

      move_iterator();
      explicit move_iterator(iterator_type i);
      template <class U> move_iterator(const move_iterator<U>& u);
      template <class U> move_iterator& operator=(const move_iterator<U>& u);

      iterator_type base() const;
      reference operator*() const;
      pointer   operator->() const;

      move_iterator& operator++();
      move_iterator  operator++(int);
      move_iterator& operator--();
      move_iterator  operator--(int);

      move_iterator  operator+ (difference_type n) const;
      move_iterator& operator+=(difference_type n);
      move_iterator  operator- (difference_type n) const;
      move_iterator& operator-=(difference_type n);
      reference operator[](difference_type n) const;
  };

  template <class Iterator1, class Iterator2>
  bool
  operator==(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator!=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator< (const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator<=(const move_iterator<Iterator1>& x, const move_iterator<Iterator>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator> (const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  bool
  operator>=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator1, class Iterator2>
  typename move_iterator<Iterator>::difference_type
  operator-(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

  template <class Iterator>
  move_iterator<Iterator>
  operator+(typename move_iterator<Iterator>::difference_type n,
            const move_iterator<Iterator>& x);

  template <class Iterator>
  move_iterator<Iterator>
  make_move_iterator(const Iterator& i);

}

24.4.3.1 - move_iterator requirements

-1- The template parameter for move_iterator shall meet the requirements for InputIterator. Additionally if any of the bidirectional or random access traversal functions are instantiated, the template parameter must additionally meet the requirements of bidirectional or random access iterator accordingly.

24.4.3.2 - move_iterator operations

24.4.3.2.1 - move_iterator constructors
move_iterator();

-1- Effects: Default constructs the move_iterator by default constructing the contained Iterator.

explicit move_iterator(iterator_type i);

-2- Effects: Constructs the move_iterator by copy constructing the contained Iterator with i.

template <class U> move_iterator(const move_iterator<U>& u);

-3- Effects: Constructs the move_iterator by constructing the contained Iterator with u.base().

-4- Requires: U must be convertible to Iterator.

24.4.3.2.2 - move_iterator assignment
template <class U> move_iterator& operator=(const move_iterator<U>& u);

-1- Effects: Assigns u.base() to the contained Iterator.

-2- Requires: U must be convertible to Iterator.

24.4.3.2.3 - move_iterator access
iterator_type base() const;

-1- Effects: Returns the contained Iterator.

reference operator*() const;

-2- Effects: Returns the result of the dereferenced contained Iterator, implicitly cast to an rvalue reference.

pointer operator->() const;

-3- Effects: Returns the contained Iterator.

24.4.3.2.4 - move_iterator traversal
move_iterator& operator++();

-1- Effects: Increments the contained Iterator.

-2- Returns: *this.

move_iterator operator++(int);

-3- Effects: Increments the contained Iterator.

-4- Returns: A copy of *this prior to the increment.

move_iterator& operator--();

-5- Effects: Decrements the contained Iterator.

-6- Returns: *this.

move_iterator operator--(int);

-7- Effects: Decrements the contained Iterator.

-8- Returns: A copy of *this prior to the decrement.

move_iterator operator+ (difference_type n) const;

-9- Effects: Adds n to a copy of the contained Iterator.

-10- Returns: The copy of the returned Iterator which had n added to it.

move_iterator& operator+=(difference_type n);

-11- Effects: Adds n to the contained Iterator.

-12- Returns: *this.

move_iterator operator- (difference_type n) const;

-13- Effects: Subtracts n from a copy of the contained Iterator.

-14- Returns: The copy of the returned Iterator which had n subtracted from it.

move_iterator& operator-=(difference_type n);

-15- Effects: Subtracts n from the contained Iterator.

-16- Returns: *this.

reference operator[](difference_type n) const;

-17- Effects: Applies n to the contained Iterator using the index operator.

-18- Returns: The result of n applied to the contained Iterator using the index operator, implicitly cast to an rvalue reference.

template <class Iterator1, class Iterator2>
typename move_iterator<Iterator>::difference_type
operator-(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

-19- Returns: x.base() - y.base().

template <class Iterator>
move_iterator<Iterator>
operator+(typename move_iterator<Iterator>::difference_type n,
          const move_iterator<Iterator>& x);

-20- Returns: move_iterator<Iterator>(x.base() + n).

24.4.3.2.5 - move_iterator comparison
template <class Iterator1, class Iterator2>
bool
operator==(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

-1- Returns: x.base() == y.base().

template <class Iterator1, class Iterator2>
bool
operator!=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

-2- Returns: !(x == y).

template <class Iterator1, class Iterator2>
bool
operator< (const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

-3- Returns: x.base() < y.base().

template <class Iterator1, class Iterator2>
bool
operator<=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

-4- Returns: !(y < x).

template <class Iterator1, class Iterator2>
bool
operator> (const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

-5- Returns: y < x.

template <class Iterator1, class Iterator2>
bool
operator>=(const move_iterator<Iterator1>& x, const move_iterator<Iterator2>& y);

-6- Returns: !(x < y).

24.4.3.2.6 - make_move_iterator
template <class Iterator>
move_iterator<Iterator>
make_move_iterator(const Iterator& i);

-1- Returns: move_iterator<Iterator>(i).