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
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:
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);
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.
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); };
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.
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); };
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.
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); };
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 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); }
-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.
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.
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.
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.
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).
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).
template <class Iterator> move_iterator<Iterator> make_move_iterator(const Iterator& i);
-1- Returns: move_iterator<Iterator>(i).