Fixing a Safety Problem with Rvalue References: Proposed Wording (Revision 1)

Authors: Douglas Gregor, David Abrahams
Contact: doug.gregor@gmail.com, dave@boostpro.com
Organization: Apple, BoostPro Computing
Date: 2009-03-05
Number: N2844=09-0034
Revises: N2831=09-0021

Introduction

N2812=08-0322 describes a safety problem with rvalue references that can cause unintentional modification of lvalues. The problem is summarized below; however, please read N2812 for a comprehensive discussion of the motivation behind this change. This paper provides proposed wording that fixes the safety problem in both the language and in the library.

Changes from N2831

The Problem

Rvalue references violate a principle which we refer to as the Principle of Type-Safe Overloading, which we express as:

Principle of Type-safe Overloading

Every function must be type-safe in isolation, without regard to how it has been overloaded.

Specifically, in the common use of rvalue references to provide overloads for both copy and move semantics, rvalue references rely on overloading behavior to provide type safety. For example, consider std::list's push_back operation:

template<typename T>
class list {
public:
   void push_back(const value_type& x); // #1
   void push_back(value_type&& x); // #2
};

Now, when we call push_back with an lvalue of a type that is movable but not copyable (here, std::unique_ptr), we see the use of overloading to ensure type-safety. For example:

void do_push_back(std::list<std::unique_ptr<int>> &l, std::unique_ptr<int> x) {
  l.push_back(x); // error: selects #1, which fails to instantiate
}

Here, overload resolution must select between the two overloads. Overload #1 is viable, since the lvalue reference to const can bind to an lvalue. Overload #2 is also viable, since an rvalue reference can bind to an lvalue. Overload resolution then selects #1 (the copying version of push_back). Later, the instantiation of #1 will fail, because std::unique_ptrs are non-copyable types.

The end result of this process is as desired: the do_push_back operation attempted to pass an lvalue to an operation (push_back) that (conceptually) does not modify its input argument, but since the argument type does not support copying, we receive an error from the compiler. To avoid the error, we would need to explicitly say that the argument should be treated as an rvalue or provide a temporary.

Despite the desirable result, the mechanism used to ensure that we receive a compilation error in this example is brittle. In particular, if for some reason overload #1 is not viable, then call l.push_back(x) will resolve to #2, and silently steal resources from an lvalue. How could overload #1 become non-viable? One possibility is the use of concepts:

   requires CopyConstructible<value_type> void push_back(const value_type& x); // #1
   requires MoveConstructible<value_type> void push_back(value_type&& x); // #2

Here, the fact that value_type is not CopyConstructible means that overload #1 is automatically non-viable (in fact, it doesn't even exist in the class template specialization std::list<std::unique_ptr<int>>), Therefore, with concepts, the call l.push_back(x) type-checks and selects #2, silently moving from lvalues.

The fundamental problem in this example is that overload #2 is violating the principle of type-safe overloading, because overload #2 in isolation is not safe: it silently steals resources from lvalues. The attempted fix for the problem, where we add additional overloads, will fail any time that those overloads can become non-viable in the overload sets. Simple uses of concepts expose this problem with rvalue references, but they aren't the only triggers: the issue can crop up due to any kind of template argument deduction failure.

This proposal eliminates the binding of rvalue references to lvalues, so that rvalue references adhere to the principle of type-safe overloading. For additional motivation and a discussion of alternatives that have been proposed, please refer to N2812=08-0322.

Proposed Changes

The language itself required relatively few changes, specifically:

The library changes are more extensive. However, most of the changes are specification changes that provide the same user-visible behavior while adhering to the new semantics of rvalue references. To achieve this goal, we:

Implementation Experience

We have produced an implementation of the proposed solution in the GNU C++ compiler, which is available as a patch against GCC 4.3.2. The actual implementation of the language change is trivial---we merely check whether the binding computed would bind an lvalue to an rvalue reference, and reject the binding in this case. The changes to the standard library are slightly more involved due to the large number of changes. We do not anticipate that this change will have any significant impact on compilers or standard library implementations. The GCC implementation required a day's effort to update both the language and the library, although more effort would certainly be required to update the test cases associated with this feature.

Proposed Wording

5.2.9 Static cast [expr.static.cast]

Add the following new paragraph after paragraph 2

  1. An lvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1" (8.5.3). The result is an rvalue of type "cv2 T2" that refers to the object or the specified base class subobject thereof. If T2 is a base class of T1, a program that necessitates such a cast is ill-formed if T2 is an inaccessible (Clause 11) or ambiguous (10.2) base class of T1.

8.5.3 References [dcl.init.ref]

Modify paragraph 5 as follows:

  1. A reference to type "cv1 T1" is initialized by an expression of type "cv2 T2" as follows:

13.3.3.2 Ranking implicit conversion sequences [over.ics.rank]

Modify paragraph 3 as follows

  1. Two implicit conversion sequences of the same form are indistinguishable conversion sequences unless one of the following rules applies:

15.3 Handling an exception [except.handle]

Modify paragraph 1 as follows:

  1. The exception-declaration in a handler describes the type(s) of exceptions that can cause that handler to be entered. The exception-declaration shall not denote an incomplete type or an rvalue reference type. The exception-declaration shall not denote a pointer or reference to an incomplete type, other than void*, const void*, volatile void*, or const volatile void*.

20.1.1 Type transformations [concept.transform]

Modify the RvalueOf concept as follows:

auto concept RvalueOf<typename T> { 
  typename type = T&&; 
  requires ExplicitlyConvertible<T&, type> && Convertible<T&&, type>; 
} 

Add the following new section

20.1.2 Type classifications [concept.classify]

  1. The concepts in 20.1.2 provide simple type classifications that can be used within constrained templates.
  2. A program shall not provide concept maps for any concept in 20.1.2
  concept LvalueReference<typename T> { }
  template<typename T> concept_map LvalueReference<T&> { }
  1. Note: determines whether a given type is an lvalue reference type.
  concept RvalueReference<typename T> { }
  template<typename T> concept_map RvalueReference<T&&> { }
  1. Note: determines whether a given type is an rvalue reference type.

20.1.3 Operator concepts [concept.operator]

Modify the HasDereference concept as follows:

auto concept HasDereference<typename T> { 
  typename result_type; 
  result_type operator*(T&);
  result_type operator*(T&&); 
}

Modify the HasSubscript concept as follows:

auto concept HasSubscript<typename T, typename U> { 
  typename result_type; 
  result_type operator[](T&, const U&);
  result_type operator[](T&&, const U&); 
}

Modify the Callable concept as follows:

auto concept Callable<typename F, typename... Args> { 
  typename result_type; 
  result_type operator()(F&, Args...);
  result_type operator()(F&&, Args...); 
}

20.2.2 forward/move helpers [forward]

Change the definitions of forward and move as follows:

  template <IdentityOf T> requires !LvalueReference<T>
    T&& forward(IdentityOf<T>::type& t); 
  template <IdentityOf T> requires LvalueReference<T>
    T&  forward(IdentityOf<T>::type& t);

  1. [ Note: The use of IdentityOf in forward forces users to explicitly specify the template parameter. This is necessary to get the correct forwarding semantics. -- end note ]
  2. Returns: static_cast<T&&>(t) or t, respectively.
  template <RvalueOf T> RvalueOf<T>::type move(T&& t);
  1. Returns: static_cast<RvalueOf<T>::type>(t)

20.2.3 Pairs [pairs]

Update the declaration of pair's swap as follows:

  requires Swappable<T1> && Swappable<T2> void swap(pair&& p);
  1. Effects: Swaps first with p.first and second with p.second.
  template<class T1, class T2> 
    requires Swappable<T1> && Swappable<T2> 
    void swap(pair<T1, T2>& x, pair<T1, T2>& y); 
  template<class T1, class T2>
    requires Swappable<T1> && Swappable<T2>
    void swap(pair<T1, T2>&& x, pair<T1, T2>& y);
  template<class T1, class T2>
    requires Swappable<T1> && Swappable<T2>
    void swap(pair<T1, T2>& x, pair<T1, T2>&& y);
  1. Effects: x.swap(y)

20.4.2.6 Tuple swap [tuple.swap]

Change the declaration of tuple's swap as follows:

  requires Swappable<Types>... void swap(tuple&& rhs);
  1. Requires: each type in Types shall be Swappable.

20.4.2.7 Tuple specialized algorithms [tuple.special]

Change the declaration of tuple's swap as follows:

template <class... Types>
  requires Swappable<Types>...
  void swap(tuple<Types...>& x, tuple<Types...>& y); 
template <class... Types>
  void swap(tuple<Types...>&& x, tuple<Types...>& y);
template <class... Types>
  void swap(tuple<Types...>& x, tuple<Types...>&& y);
  1. Effects: x.swap(y)

20.6.16.2.2 function modifiers [func.wrap.func.mod]

Change the declaration of function's swap as follows:

void swap(function&& other); 
  1. Effects: interchanges the targets of *this and other.
  2. Throws: nothing.

20.7.12.2.5 unique_ptr modifiers [unique.ptr.single.modifiers]

Change the declaration of unique_ptr's swap as follows:

  void swap(unique_ptr&& u);
  1. Requires: The deleter D shall be Swappable and shall not throw an exception under swap.
  2. Effects: The stored pointers of this and u are exchanged. The stored deleters are swap'd (un-qualified).
  3. Throws: nothing.

20.7.12.4 unique_ptr specialized algorithms [unique.ptr.special]

Change the declaration of unique_ptr's swap as follows:

template <class T, class D> void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y); 
template <class T, class D> void swap(unique_ptr<T, D>&& x, unique_ptr<T, D>& y); 
template <class T, class D> void swap(unique_ptr<T, D>& x, unique_ptr<T, D>& y);
  1. Effects: Calls x.swap(y).

20.7.13.2.4 shared_ptr modifiers [util.smartptr.shared.mod]

Change the declaration of shared_ptr's swap as follows:

void swap(shared_ptr&& r);
  1. Effects: Exchanges the contents of *this and r.
  2. Throws: nothing.

20.7.13.2.9 shared_ptr specialized algorithms [util.smartptr.shared.spec]

Change the declaration of shared_ptr's swap as follows:

template<class T> void swap(shared_ptr<T>& a, shared_ptr<T>& b); 
template<class T> void swap(shared_ptr<T>&& a, shared_ptr<T>& b);
template<class T> void swap(shared_ptr<T>& a, shared_ptr<T>&& b);
  1. Effects: Equivalent to a.swap(b).
  2. Throws: nothing.

21.3.6.8 basic_string::swap [string::swap]

Change the declaration of basic_string's swap as follows:

void swap(basic_string<charT,traits,Allocator>&& s);
  1. Throws: Nothing.
  2. Postcondition: *this contains the same sequence of characters that was in s, s contains the same sequence of characters that was in *this.
  3. Complexity: constant time.

21.3.8.8 swap [string.special]

Change the declaration of basic_string's swap as follows:

template<class charT, class traits, class Allocator> 
  void swap(basic_string<charT,traits,Allocator>& lhs, 
            basic_string<charT,traits,Allocator>& rhs); 
template<class charT, class traits, class Allocator>
  void swap(basic_string<charT,traits,Allocator>&& lhs,
            basic_string<charT,traits,Allocator>& rhs);
template<class charT, class traits, class Allocator>
  void swap(basic_string<charT,traits,Allocator>& lhs,
            basic_string<charT,traits,Allocator>&& rhs);
  1. Effects: lhs.swap(rhs);

21.3.8.9 Inserters and extractors [string.io]

Change the declaration of basic_string's operator>> as follows:

template<class charT, class traits, class Allocator> 
  basic_istream<charT,traits>& 
   operator>>(basic_istream<charT,traits>&& is, 
              basic_string<charT,traits,Allocator>& str);

Change the declaration of basic_string's operator<< as follows:

template<class charT, class traits, class Allocator> 
  basic_ostream<charT, traits>& 
    operator<<(basic_ostream<charT, traits>&& os, 
               const basic_string<charT,traits,Allocator>& str);

Add a second declaration of basic_string's getline prior to paragraph 7 as follows:

template<class charT, class traits, class Allocator>
  basic_istream<charT,traits>&
    getline(basic_istream<charT,traits>& is,
            basic_string<charT,traits,Allocator>& str,
            charT delim);
template<class charT, class traits, class Allocator> 
  basic_istream<charT,traits>& 
    getline(basic_istream<charT,traits>&& is, 
            basic_string<charT,traits,Allocator>& str, 
            charT delim);

Add a second declaration of basic_string's getline prior to paragraph 11 as follows:

template<class charT, class traits, class Allocator>
  basic_istream<charT,traits>&
    getline(basic_istream<charT,traits>& is,
            basic_string<charT,traits,Allocator>& str);
template<class charT, class traits, class Allocator> 
  basic_istream<charT,traits>& 
    getline(basic_istream<charT,traits>&& is, 
            basic_string<charT,traits,Allocator>& str);

23.2.2 Class template deque [deque]

Change the declaration of deque's swap as follows:

void swap(deque<T,Alloc>&&); 

23.2.2.4 deque specialized algorithms [deque.special]

Change the declaration of deque's swap as follows:

template <ValueType T, class Alloc> 
  void swap(deque<T,Alloc>& x, deque<T,Alloc>& y); 
template <ValueType T, class Alloc>
  void swap(deque<T,Alloc>&& x, deque<T,Alloc>& y);
template <ValueType T, class Alloc>
  void swap(deque<T,Alloc>& x, deque<T,Alloc>&& y);
  1. Effects: x.swap(y);

23.2.3 Class template forward_list [forwardlist]

Change the declaration of forward_list's swap as follows:

void swap(forward_list<T,Alloc>&&); 

23.2.3.6 forward_list specialized algorithms [forwardlist.spec]

Change the declaration of forward_list's swap as follows:

template <ValueType T, class Alloc> 
  void swap(forward_list<T,Alloc>& x, forward_list<T,Alloc>& y); 
template <ValueType T, class Alloc>
  void swap(forward_list<T,Alloc>&& x, forward_list<T,Alloc>& y);
template <ValueType T, class Alloc>
  void swap(forward_list<T,Alloc>& x, forward_list<T,Alloc>&& y);
  1. Effects: x.swap(y)

23.2.4 Class template list [list]

Change the declaration of list's swap as follows:

  void swap(list<T,Alloc>&&); 

23.2.4.5 list specialized algorithms [list.special]

Change the declaration of list's swap as follows:

template <ValueType T, class Alloc> 
  void swap(list<T,Alloc>& x, list<T,Alloc>& y);
template <ValueType T, class Alloc>
  void swap(list<T,Alloc>&& x, list<T,Alloc>& y);
template <ValueType T, class Alloc>
  void swap(list<T,Alloc>& x, list<T,Alloc>&& y);
  1. Effects: x.swap(y);

23.2.5.1.1 queue definition [queue.defn]

Change the definition of queue's swap as follows:

  void swap(queue&& q) { swap(c, q.c); }

23.2.5.1.3 queue specialized algorithms [queue.special]

Change the declaration of queue's swap as follows:

template <ObjectType T, Swappable Cont> 
  void swap(queue<T, Cont>& x, queue<T, Cont>& y); 
template <ObjectType T, Swappable Cont>
  void swap(queue<T, Cont>&& x, queue<T, Cont>& y);
template <ObjectType T, Swappable Cont> 
  void swap(queue<T, Cont>& x, queue<T, Cont>&& y);
  1. Effects: x.swap(y).

23.2.5.2 Class template priority_queue [priority.queue]

Change the declaration of priority_queue's swap as follows:

requires Swappable<Cont>
  void swap(priority_queue&&); 

23.2.5.2.3 priority_queue specialized algorithms [priqueue.special]

Change the declaration of priority_queue's swap as follows:

template <class T, Swappable Cont, Swappable Compare> 
  void swap(priority_queue<T, Cont, Compare>& x, priority_queue<T, Cont, Compare>& y); 
template <class T, Swappable Cont, Swappable Compare>
  void swap(priority_queue<T, Cont, Compare>&& x, priority_queue<T, Cont, Compare>& y);
template <class T, Swappable Cont, Swappable Compare>
  void swap(priority_queue<T, Cont, Compare>& x, priority_queue<T, Cont, Compare>&& y);
  1. Effects: x.swap(y).

23.2.5.3.1 stack definition [stack.defn]

Change the definition of stack's swap as follows:

requires Swappable<Cont>
  void swap(stack&& s) { swap(c, s.c); } 

23.2.5.3.3 stack specialized algorithms [stack.special]

template <ObjectType T, Swappable Cont> 
  void swap(stack<T, Cont>& x, stack<T, Cont>& y); 
template <ObjectType T, Swappable Cont>
  void swap(stack<T, Cont>&& x, stack<T, Cont>& y); 
template <ObjectType T, Swappable Cont> 
  void swap(stack<T, Cont>& x, stack<T, Cont>&& y);
  1. Effects: x.swap(y).

23.2.6 Class template vector [vector]

Change the declaration of vector's swap as follows:

  void swap(vector<T,Alloc>&&); 

23.2.6.2 vector capacity [vector.capacity]

Modify the declaration of vector's swap prior to paragraph 8 as follows:

  void swap(vector<T,Alloc>&&); 

23.2.6.5 vector specialized algorithms [vector.special]

Change the declaration of vector's swap as follows:

template <ValueType T, class Alloc> 
  void swap(vector<T,Alloc>& x, vector<T,Alloc>& y); 
template <ValueType T, class Alloc>
  void swap(vector<T,Alloc>&& x, vector<T,Alloc>& y); 
template <ValueType T, class Alloc>
  void swap(vector<T,Alloc>& x, vector<T,Alloc>&& y);
  1. Effects: x.swap(y);

23.2.7 Class vector<bool> [vector.bool]

Change the declaration of vector<bool>'s swap as follows:

void swap(vector<bool,Alloc>&&);

23.3.1 Class template map [map]

Change the declaration of map's swap as follows:

void swap(map<Key,T,Compare,Alloc>&&);

23.3.1.5 map specialized algorithms [map.special]

Remove map's swap algorithms that operate on rvalue references:

template <ValueType Key, ValueType T, class Compare, class Alloc> 
  void swap(map<Key,T,Compare,Alloc>& x, 
            map<Key,T,Compare,Alloc>& y); 
template <ValueType Key, ValueType T, class Compare, class Alloc>
  void swap(map<Key,T,Compare,Alloc>&& x,
            map<Key,T,Compare,Alloc>& y); 
template <ValueType Key, ValueType T, class Compare, class Alloc> 
  void swap(map<Key,T,Compare,Alloc>& x,
            map<Key,T,Compare,Alloc>&& y);

23.3.2 Class template multimap [multimap]

Change the declaration of multimap's swap as follows:

void swap(multimap<Key,T,Compare,Alloc>&&);

23.3.2.4 multimap specialized algorithms [multimap.special]

Remove multimap's swap algorithms that operate on rvalue references:

template <ValueType Key, ValueType T, class Compare, class Alloc> 
  void swap(multimap<Key,T,Compare,Alloc>& x, 
            multimap<Key,T,Compare,Alloc>& y); 
template <ValueType Key, ValueType T, class Compare, class Alloc>
  void swap(multimap<Key,T,Compare,Alloc>&& x,
            multimap<Key,T,Compare,Alloc>& y); 
template <ValueType Key, ValueType T, class Compare, class Alloc> 
  void swap(multimap<Key,T,Compare,Alloc>& x,
            multimap<Key,T,Compare,Alloc>&& y);

23.3.3 Class template set [set]

Change the declaration of set's swap as follows:

void swap(set<Key,T,Compare,Alloc>&&);

23.3.3.2 set specialized algorithms [set.special]

Remove set's swap algorithms that operate on rvalue references:

template <ValueType Key, ValueType T, class Compare, class Alloc> 
  void swap(set<Key,T,Compare,Alloc>& x, 
            set<Key,T,Compare,Alloc>& y); 
template <ValueType Key, ValueType T, class Compare, class Alloc>
  void swap(set<Key,T,Compare,Alloc>&& x,
            set<Key,T,Compare,Alloc>& y); 
template <ValueType Key, ValueType T, class Compare, class Alloc> 
  void swap(set<Key,T,Compare,Alloc>& x,
            set<Key,T,Compare,Alloc>&& y);

23.3.4 Class template multiset [multiset]

Change the declaration of multiset's swap as follows:

void swap(multiset<Key,T,Compare,Alloc>&&);

23.3.4.2 multiset specialized algorithms [multiset.special]

Remove multiset's swap algorithms that operate on rvalue references:

template <ValueType Key, ValueType T, class Compare, class Alloc> 
  void swap(multiset<Key,T,Compare,Alloc>& x, 
            multiset<Key,T,Compare,Alloc>& y); 
template <ValueType Key, ValueType T, class Compare, class Alloc>
  void swap(multiset<Key,T,Compare,Alloc>&& x,
            multiset<Key,T,Compare,Alloc>& y); 
template <ValueType Key, ValueType T, class Compare, class Alloc> 
  void swap(multiset<Key,T,Compare,Alloc>& x,
            multiset<Key,T,Compare,Alloc>&& y);

23.4.1 Class template unordered_map [unord.map]

Change the declaration of unordered_map's swap as follows:

  void swap(unordered_map&&);

23.4.1.3 unordered_map swap [unord.map.swap]

Remove unordered_map's swap algorithms that operate on rvalue references:

template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc> 
  void swap(unordered_map<Key, T, Hash, Pred, Alloc>& x, 
            unordered_map<Key, T, Hash, Pred, Alloc>& y); 
template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc>
  void swap(unordered_map<Key, T, Hash, Pred, Alloc>& x, 
            unordered_map<Key, T, Hash, Pred, Alloc>&& y); 
template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc> 
  void swap(unordered_map<Key, T, Hash, Pred, Alloc>&& x, 
            unordered_map<Key, T, Hash, Pred, Alloc>& y); 

23.4.2 Class template unordered_multimap [unord.multimap]

Change the declaration of unordered_multimap's swap as follows:

  void swap(unordered_multimap&&);

23.4.2.2 unordered_multimap swap [unord.multimap.swap]

Remove unordered_multimap's swap algorithms that operate on rvalue references:

template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc> 
  void swap(unordered_multimap<Key, T, Hash, Pred, Alloc>& x, 
            unordered_multimap<Key, T, Hash, Pred, Alloc>& y); 
template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc>
  void swap(unordered_multimap<Key, T, Hash, Pred, Alloc>& x, 
            unordered_multimap<Key, T, Hash, Pred, Alloc>&& y); 
template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc> 
  void swap(unordered_multimap<Key, T, Hash, Pred, Alloc>&& x, 
            unordered_multimap<Key, T, Hash, Pred, Alloc>& y); 

23.4.3 Class template unordered_set [unord.set]

Change the declaration of unordered_set's swap as follows:

  void swap(unordered_set&&);

23.4.3.2 unordered_set swap [unord.set.swap]

Remove unordered_set's swap algorithms that operate on rvalue references:

template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc> 
  void swap(unordered_set<Key, T, Hash, Pred, Alloc>& x, 
            unordered_set<Key, T, Hash, Pred, Alloc>& y); 
template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc>
  void swap(unordered_set<Key, T, Hash, Pred, Alloc>& x, 
            unordered_set<Key, T, Hash, Pred, Alloc>&& y); 
template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc> 
  void swap(unordered_set<Key, T, Hash, Pred, Alloc>&& x, 
            unordered_set<Key, T, Hash, Pred, Alloc>& y); 

23.4.4 Class template unordered_multiset [unord.multiset]

Change the declaration of unordered_multiset's swap as follows:

  void swap(unordered_multiset&&);

23.4.4.2 unordered_multiset swap [unord.multiset.swap]

Remove unordered_multiset's swap algorithms that operate on rvalue references:

template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc> 
  void swap(unordered_multiset<Key, T, Hash, Pred, Alloc>& x, 
            unordered_multiset<Key, T, Hash, Pred, Alloc>& y); 
template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc>
  void swap(unordered_multiset<Key, T, Hash, Pred, Alloc>& x, 
            unordered_multiset<Key, T, Hash, Pred, Alloc>&& y); 
template <ValueType Key, ValueType T, class Hash, class Pred, class Alloc> 
  void swap(unordered_multiset<Key, T, Hash, Pred, Alloc>&& x, 
            unordered_multiset<Key, T, Hash, Pred, Alloc>& y); 

24.1.1 Iterator [iterator.iterators]

Change the iterator concept as follows:

concept Iterator<typename X> : Semiregular<X> { 
  MoveConstructible reference = typename X::reference; 
  MoveConstructible postincrement_result; 
  requires HasDereference<postincrement_result>; 
  reference operator*(X&);
  reference operator*(X&&); 
  X& operator++(X&); 
  postincrement_result operator++(X&, int); 
}

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

reference operator*() const;
  1. Returns: std::move(*current), implicitly converted to an rvalue reference.

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

requires RandomAccessIterator 
  unspecified operator[](difference_type n) const;
  1. Returns: std::move(current[n]), implicitly converted to an rvalue reference.

26.5.2 Class template valarray [template.valarray]

Change the declaration of valarray's swap as follows:

  void swap(valarray&&); 

26.5.2.7 valarray member functions [valarray.members]

Change the declaration of valarray's swap as follows:

  void swap(valarray&&); 

26.5.3.4 valarray specialized algorithms [valarray.special]

Remove valarray's swap specialized algorithms that use rvalue references as follows:

template <class T> void swap(valarray<T>& x, valarray<T>& y); 
template <class T> void swap(valarray<T>&& x, valarray<T>& y);
template <class T> void swap(valarray<T>& x, valarray<T>&& y);

27.4.4 Class template basic_ios [ios]

Change the declaration of basic_ios's swap as follows:

  void swap(basic_ios&& rhs);

27.4.4.2 Member functions [basic.ios.members]

Modify the declaration of basic_ios's swap prior to paragraph 21 as follows:

  void swap(basic_ios&& rhs);

27.5.2 Class template basic_streambuf [streambuf]

Change the declaration of basic_streambuf's swap as follows:

  void swap(basic_streambuf&& rhs);

27.5.2.3.1 Assignment [streambuf.assign]

Change the declaration of basic_streambuf's swap before paragraph 4 as follows:

  void swap(basic_streambuf&& rhs);

27.6 Formatting and manipulators [iostream.format]

Modify the header <istream> synopsis as follows:

namespace std {
  template <class charT, class traits = char_traits<charT> >
    class basic_istream; 

  typedef basic_istream<char> istream; 
  typedef basic_istream<wchar_t> wistream; 
  template <class charT, class traits = char_traits<charT> > 
    class basic_iostream; 
  typedef basic_iostream<char> iostream; 
  typedef basic_iostream<wchar_t> wiostream;

  template <class charT, class traits> 
    basic_istream<charT,traits>& ws(basic_istream<charT,traits>& is);

  template<typename charT, typename traits, typename T>
    basic_istream<charT, traits>&
    operator>>(basic_istream<charT, traits>&& is, T& x);
}

Modify the header <ostream> synopsis as follows:

namespace std { 
  template <class charT, class traits = char_traits<charT> > 
    class basic_ostream; 
  typedef basic_ostream<char> ostream; 
  typedef basic_ostream<wchar_t> wostream;

  template <class charT, class traits> 
    basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os); 
  template <class charT, class traits> 
    basic_ostream<charT,traits>& ends(basic_ostream<charT,traits>& os); 
  template <class charT, class traits> 
    basic_ostream<charT,traits>& flush(basic_ostream<charT,traits>& os); 

  template<typename charT, typename traits, typename T>
    basic_ostream<charT, traits>&
    operator<<(basic_ostream<charT, traits>&& os, const T& x);
}

27.6.1 Input streams [input.streams]

  1. The header <istream> defines two types and a function signature that control input from a stream buffer along with a function template that performs extraction from stream rvalues.

27.6.1.1 Class template basic_istream [istream]

Change the declaration of basic_istream's swap as follows:

  void swap(basic_istream&& rhs);

27.6.1.1.2 Class basic_istream assign and swap [istream.assign]

Change the declaration of basic_istream's swap as follows:

  void swap(basic_istream&& rhs);

Remove the rvalue-reference overloads of basic_istream's swap as follows:

template <class charT, class traits> 
  void swap(basic_istream<charT, traits>& x, basic_istream<charT, traits>& y); 
template <class charT, class traits>
  void swap(basic_istream<charT, traits>&& x, basic_istream<charT, traits>& y);
template <class charT, class traits>
  void swap(basic_istream<charT, traits>& x, basic_istream<charT, traits>&& y);

27.6.1.2.3 basic_istream::operator>> [istream::extractors]

Change the declarations of basic_istream's operator>> prior to paragraph 7 as follows:

template<class charT, class traits> 
  basic_istream<charT,traits>& operator>>(basic_istream<charT,traits>&& in, 
                                          charT* s); 
template<class traits> 
  basic_istream<char,traits>& operator>>(basic_istream<char,traits>&& in, 
                                         unsigned char* s); 
template<class traits> 
  basic_istream<char,traits>& operator>>(basic_istream<char,traits>&& in,
                                         signed char* s);

Change the declarations of basic_istream's operator>> prior to paragraph 12 as follows:

template<class charT, class traits> 
  basic_istream<charT,traits>& operator>>(basic_istream<charT,traits>&& in, 
                                          charT& c); 
template<class traits> 
  basic_istream<char,traits>& operator>>(basic_istream<char,traits>&& in, 
                                         unsigned char& c); 
template<class traits> 
  basic_istream<char,traits>& operator>>(basic_istream<char,traits>&& in, 
                                         signed char& c); 

27.6.1.5 Class template basic_iostream [iostreamclass]

Change the declaration of basic_iostream's swap as follows:

  void swap(basic_iostream&& rhs);

27.6.1.5.3 basic_iostream assign and swap [iostream.assign]

Change the declaration of basic_iostream's swap prior to paragraph 2 as follows:

  void swap(basic_iostream&& rhs);

Change the declaration of basic_iostream's swap prior to paragraph 4 as follows:

template <class charT, class traits> 
  void swap(basic_iostream<charT, traits>& x, basic_iostream<charT, traits>& y); 
template <class charT, class traits>
  void swap(basic_iostream<charT, traits>&& x, basic_iostream<charT, traits>& y); 
template <class charT, class traits> 
  void swap(basic_iostream<charT, traits>& x, basic_iostream<charT, traits>&& y);

Add the following new section:

27.6.1.6 Rvalue stream extraction [istream.rvalue]

template<typename charT, typename traits, typename T>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>&& is, T& x);
  1. Effects: is >> x
  2. Returns: is

27.6.2 Output streams [output.streams]

  1. The header <ostream> defines a type and several function signatures that control output to a stream buffer along with a function template that performs insertion into stream rvalues.

27.6.2.1 Class template basic_ostream [ostream]

Change the declaration of basic_ostream's swap as follows:

  void swap(basic_ostream&& rhs);

27.6.2.3 Class basic_ostream assign and swap [ostream.assign]

Change the declaration of basic_ostream's swap prior to paragraph 3 as follows:

  void swap(basic_ostream&& rhs);

Change the declaration of basic_ostream's swap prior to paragraph 4 as follows:

template <class charT, class traits> 
  void swap(basic_ostream<charT, traits>& x, basic_ostream<charT, traits>& y); 
template <class charT, class traits>
  void swap(basic_ostream<charT, traits>&& x, basic_ostream<charT, traits>& y);
template <class charT, class traits>
  void swap(basic_ostream<charT, traits>& x, basic_ostream<charT, traits>&& y);

27.6.2.6.4 Character inserter function templates [ostream.inserters.character]

Remove the rvalue-reference overloads of basic_ostream's inserter function templates prior to paragraph 1 as follows:

template<class charT, class traits> 
  basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, 
                                          charT c); 
template<class charT, class traits>
  basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&& out,
                                          charT c);
template<class charT, class traits> 
  basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, 
                                          char c);
template<class charT, class traits> 
  basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&& out,
                                          char c);
// specialization 
template<class traits> 
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, 
                                          char c); 
template<class traits>
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&& out,
                                          char c);
// signed and unsigned 
template<class traits> 
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, 
                                          signed char c); 
template<class traits>
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&& out,
                                          signed char c);
template<class traits> 
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, 
un                                          signed char c); 
template<class traits>
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&& out,
                                          unsigned char c);

Remove the rvalue-reference overloads of basic_ostream's inserter function templates prior to paragraph 3 as follows:

template<class charT, class traits> 
  basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, 
                                          const charT* s); 
template<class charT, class traits>
  basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&& out,
                                          const charT* s);
template<class charT, class traits> 
  basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, 
                                          const char* s); 
template<class charT, class traits>
  basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&& out,
                                          const char* s);
template<class traits>
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, 
                                          const char* s); 
template<class traits>
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&& out,
                                          const char* s);
template<class traits> 
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, 
                                          const signed char* s); 
template<class traits>
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&& out,
                                          const signed char* s);
template<class traits> 
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, 
                                          const unsigned char* s); 
template<class traits>
  basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&& out,
                                          const unsigned char* s);

27.6.2.9 Rvalue stream insertion [ostream.rvalue]

template<typename charT, typename traits, typename T>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>&& os, const T& x);
  1. Effects: os << x
  2. Returns: os

27.7.1 Class template basic_stringbuf [stringbuf]

Change the declaration of basic_stringbuf's swap as follows:

  void swap(basic_stringbuf&& rhs);

27.7.1.2 Assign and swap [stringbuf.assign]

Change the declaration of basic_stringbuf's swap prior to paragraph 3 as follows:

  void swap(basic_stringbuf&& rhs);

Change the declaration of basic_stringbuf's swap prior to paragraph 4 as follows:

template <class charT, class traits, class Allocator> 
  void swap(basic_stringbuf<charT, traits, Allocator>& x, 
            basic_stringbuf<charT, traits, Allocator>& y); 
template <class charT, class traits, class Allocator>
  void swap(basic_stringbuf<charT, traits, Allocator>&& x,
            basic_stringbuf<charT, traits, Allocator>& y);
template <class charT, class traits, class Allocator>
  void swap(basic_stringbuf<charT, traits, Allocator>& x,
            basic_stringbuf<charT, traits, Allocator>&& y);

27.7.2 Class template basic_istringstream [istringstream]

Change the declaration of basic_istringstream's swap as follows:

  void swap(basic_istringstream&& rhs);

27.7.2.2 Assign and swap [istringstream.assign]

Change the declaration of basic_istringstream's swap prior to paragraph 3 as follows:

  void swap(basic_istringstream&& rhs);

Change the declaration of basic_istringstream's swap prior to paragraph 4 as follows:

template <class charT, class traits, class Allocator> 
  void swap(basic_istringstream<charT, traits, Allocator>& x, 
            basic_istringstream<charT, traits, Allocator>& y); 
template <class charT, class traits, class Allocator>
  void swap(basic_istringstream<charT, traits, Allocator>&& x,
            basic_istringstream<charT, traits, Allocator>& y);
template <class charT, class traits, class Allocator>
  void swap(basic_istringstream<charT, traits, Allocator>& x,
            basic_istringstream<charT, traits, Allocator>&& y);

27.7.3 Class template basic_ostringstream [ostringstream]

Change the declaration of basic_ostringstream's swap as follows:

  void swap(basic_ostringstream&& rhs);

27.7.3.2 Assign and swap [ostringstream.assign]

Change the declaration of basic_ostringstream's swap prior to paragraph 3 as follows:

  void swap(basic_ostringstream&& rhs);

Change the declaration of basic_ostringstream's swap prior to paragraph 4 as follows:

template <class charT, class traits, class Allocator> 
  void swap(basic_ostringstream<charT, traits, Allocator>& x, 
            basic_ostringstream<charT, traits, Allocator>& y); 
template <class charT, class traits, class Allocator>
  void swap(basic_ostringstream<charT, traits, Allocator>&& x,
            basic_ostringstream<charT, traits, Allocator>& y);
template <class charT, class traits, class Allocator>
  void swap(basic_ostringstream<charT, traits, Allocator>& x,
            basic_ostringstream<charT, traits, Allocator>&& y);

27.7.4 Class template basic_stringstream [stringstream]

Change the declaration of basic_stringstream's swap as follows:

  void swap(basic_stringstream&& rhs);

27.7.4.2 Assign and swap [stringstream.assign]

Change the declaration of basic_stringstream's swap prior to paragraph 3 as follows:

  void swap(basic_stringstream&& rhs);

Change the declaration of basic_stringstream's swap prior to paragraph 4 as follows:

template <class charT, class traits, class Allocator> 
  void swap(basic_stringstream<charT, traits, Allocator>& x, 
            basic_stringstream<charT, traits, Allocator>& y); 
template <class charT, class traits, class Allocator>
  void swap(basic_stringstream<charT, traits, Allocator>&& x,
            basic_stringstream<charT, traits, Allocator>& y);
template <class charT, class traits, class Allocator>
  void swap(basic_stringstream<charT, traits, Allocator>& x,
            basic_stringstream<charT, traits, Allocator>&& y);

27.8.1.1 Class template basic_filebuf [filebuf]

Change the declaration of basic_filebuf's swap as follows:

  void swap(basic_filebuf&& rhs);

27.8.1.3 Assign and swap [filebuf.assign]

Change the declaration of basic_filebuf's swap prior to paragraph 3 as follows:

  void swap(basic_filebuf&& rhs);

Change the declaration of basic_filebuf's swap prior to paragraph 4 as follows:

template <class charT, class traits> 
  void swap(basic_filebuf<charT, traits>& x, 
            basic_filebuf<charT, traits>& y); 
template <class charT, class traits>
  void swap(basic_filebuf<charT, traits>&& x,
            basic_filebuf<charT, traits>& y);
template <class charT, class traits>
  void swap(basic_filebuf<charT, traits>& x,
            basic_filebuf<charT, traits>&& y);

27.8.1.6 Class template basic_ifstream [ifstream]

Change the declaration of basic_ifstream's swap as follows:

  void swap(basic_ifstream&& rhs);

27.8.1.8 Assign and swap [ifstream.assign]

Change the declaration of basic_ifstream's swap prior to paragraph 3 as follows:

  void swap(basic_ifstream&& rhs);

Change the declaration of basic_ifstream's swap prior to paragraph 4 as follows:

template <class charT, class traits> 
  void swap(basic_ifstream<charT, traits>& x, 
            basic_ifstream<charT, traits>& y); 
template <class charT, class traits>
  void swap(basic_ifstream<charT, traits>&& x,
            basic_ifstream<charT, traits>& y);
template <class charT, class traits>
  void swap(basic_ifstream<charT, traits>& x,
            basic_ifstream<charT, traits>&& y);

27.8.1.10 Class template basic_ofstream [ofstream]

Change the declaration of basic_ofstream's swap as follows:

  void swap(basic_ofstream&& rhs);

27.8.1.12 Assign and swap [ofstream.assign]

Change the declaration of basic_ofstream's swap prior to paragraph 3 as follows:

  void swap(basic_ofstream&& rhs);

Change the declaration of basic_ofstream's swap prior to paragraph 4 as follows:

template <class charT, class traits> 
  void swap(basic_ofstream<charT, traits>& x, 
            basic_ofstream<charT, traits>& y); 
template <class charT, class traits>
  void swap(basic_ofstream<charT, traits>&& x,
            basic_ofstream<charT, traits>& y);
template <class charT, class traits>
  void swap(basic_ofstream<charT, traits>& x,
            basic_ofstream<charT, traits>&& y);

27.8.1.14 Class template basic_fstream [fstream]

Change the declaration of basic_fstream's swap as follows:

  void swap(basic_fstream&& rhs);

27.8.1.16 Assign and swap [fstream.assign]

Change the declaration of basic_fstream's swap prior to paragraph 3 as follows:

  void swap(basic_fstream&& rhs);

Change the declaration of basic_fstream's swap prior to paragraph 4 as follows:

template <class charT, class traits> 
  void swap(basic_fstream<charT, traits>& x, 
            basic_fstream<charT, traits>& y); 
template <class charT, class traits>
  void swap(basic_fstream<charT, traits>&& x,
            basic_fstream<charT, traits>& y);
template <class charT, class traits>
  void swap(basic_fstream<charT, traits>& x,
            basic_fstream<charT, traits>&& y);

30.2.1 Class thread [thread.thread.class]

Change the declaration of thread's swap as follows:

  void swap(thread&&);

30.2.1.1 Class thread::id [thread.thread.id]

Change the declaration of thread's operator<< prior to paragraph 18 as follows:

template<class charT, class traits> 
  basic_ostream<charT, traits>& 
  operator<< (basic_ostream<charT, traits>&& out, thread::id id); 

30.2.1.5 thread members [thread.thread.member]

Change the declaration of thread's swap as follows:

  void swap(thread&&);

30.2.1.7 thread specialized algorithms [thread.thread.algorithm]

Remove the rvalue-reference overloads of thread's swap as follows:

void swap(thread& x, thread& y); 
void swap(thread&& x, thread& y);
void swap(thread& x, thread&& y);

30.3.3.2 Class template unique_lock [thread.lock.unique]

Change the declaration of unique_lock's swap as follows:

  void swap(unique_lock&& u);

30.3.3.2.3 unique_lock modifiers [thread.lock.unique.mod]

Change the declaration of unique_lock's swap as follows:

  void swap(unique_lock&& u);

Remove the rvalue-reference overloads of unique_ptr's swap as follows:

template <class Mutex> 
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>& y); 
template <class Mutex> 
  void swap(unique_lock<Mutex>&& x, unique_lock<Mutex>& y); 
template <class Mutex> 
  void swap(unique_lock<Mutex>& x, unique_lock<Mutex>&& y); 

30.5.8 Class template packaged_task [futures.task]

Change the declaration of packaged_task's swap as follows:

  void swap(packaged_task&& other);

Last modified: Thu Mar 5 13:37:53 EST 2009