Authors: Douglas Gregor, David Abrahams
Contact: doug.gregor@gmail.com, dave@boostpro.com
Organization: Apple, BoostPro Computing
Date: 2009-02-07
Number: N2831=09-0021
Revises: N2812=08-0322
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.
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_ptr
s 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.
The language itself required relatively few changes, specifically:
static_cast
an lvalue to an rvalue without creating a temporary.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:
std::forward
and std::move
to provide the same user interface under the new reference-binding rules.LvalueReference
and RvalueReference
; the former is required for std::forward
, the latter for consistency.swap
functions throughout the library, removing rvalue-reference overloads and using lvalue references for the arguments to swap
. This addresses library issue 884 and follows the guidance of an informal vote of the LWG to remove these functions.Swappable
requirements to tuple
's swap
.operator*
associated function to the Iterator
and HasDereference
concepts to permit dereferencing lvalue iterators.operator<<
and operator>>
overloads that accept an rvalue stream and forward that stream (as an lvalue) to the appropriate operator, so that the C++0x library still supports the use of rvalue streams throughout.getline
functions into four functions to support both lvalue and rvalue streams.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.
Add the following new paragraph after paragraph 2
Modify paragraph 5 as follows:
double d = 2.0; double& rd = d; // rd refers to d const double& rcd = d; // rcd refers to d struct A { }; struct B : A { } b; A& ra = b; // ra refers to A subobject in b const A& rca = b; // rca refers to A subobject in b-- end example ]
double& rd2 = 2.0; // error: not an lvalue and reference not const int i = 2; double& rd3 = i; // error: type mismatch and reference not const double&& rd4 = i; // OK: reference bound to temporary double-- end example ]
struct A { }; struct B : A { } b; extern B f(); const A& rca = f(); // Bound to the A subobject of the B rvalue. A&& rcb = f(); // Same as above-- end example ]
const double& rcd2 = 2; // rcd2 refers to temporary with value 2.0 double&& rcd3 = 2; // rcd3 refers to temporary with value 2.0 const volatile int cvi = 1; const int& r = cvi; // error: type qualifiers dropped-- end example ]
Modify paragraph 3 as follows
int f(const int *); int f(int *); int i; int j = f(&i); // calls f(int*)-- end example ] or, if not that,
int i; int f(); int g(const int&); int g(const int&&); int j = g(i); // calls g(const int&) int k = g(f()); // calls g(const int&&) struct A { A& operator<<(int); void p() &; void p() &&; }; A& operator<<(A&&, char); A() << 1; // calls A::operator<<(int) A() << 'c'; // calls operator<<(A&&, char) A a; a << 1; // calls A::operator<<(int) a << 'c'; // calls-- end example ] or, if not that,operator<<(A&&, char)A::operator<<(int) A().p(); // calls A::p()&& a.p(); // calls A::p()&
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
concept LvalueReference<typename T> { } template<typename T> concept_map LvalueReference<T&> { }
concept RvalueReference<typename T> { } template<typename T> concept_map RvalueReference<T&&> { }
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...); }
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);
static_cast<T&&>(t)
or t
, respectively.template <RvalueOf T> RvalueOf<T>::type move(T&& t);
static_cast<RvalueOf<T>::type>(t)
Update the declaration of pair's swap
as follows:
requires Swappable<T1> && Swappable<T2> void swap(pair&&p);
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);
x.swap(y)
Change the declaration of tuple's swap
as follows:
requires Swappable<Types>... void swap(tuple&&rhs);
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);
x.swap(y)
Change the declaration of function's swap
as
follows:
void swap(function&&other);
*this
and other. Change the declaration of unique_ptr's swap
as
follows:
void swap(unique_ptr&&u);
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);
x.swap(y)
.Change the declaration of shared_ptr's swap
as
follows:
void swap(shared_ptr&&r);
*this
and r
.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);
a.swap(b)
.Change the declaration of basic_string's swap
as follows:
void swap(basic_string<charT,traits,Allocator>&&s);
*this
contains the same sequence of characters that was in s, s contains the same sequence of characters that was in *this
.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);
lhs.swap(rhs);
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);
Change the declaration of deque's swap
as follows:
void swap(deque<T,Alloc>&&);
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);
x.swap(y);
Change the declaration of forward_list's swap
as follows:
void swap(forward_list<T,Alloc>&&);
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);
Change the declaration of list's swap
as follows:
void swap(list<T,Alloc>&&);
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);
Change the definition of queue's swap
as follows:
void swap(queue&&q) { swap(c, q.c); }
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);
Change the declaration of priority_queue's swap
as follows:
requires Swappable<Cont> void swap(priority_queue&&);
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);
Change the definition of stack's swap
as follows:
requires Swappable<Cont> void swap(stack&&s) { swap(c, s.c); }
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);
Change the declaration of vector's swap
as follows:
void swap(vector<T,Alloc>&&);
Modify the declaration of vector's swap
prior to paragraph 8 as follows:
void swap(vector<T,Alloc>&&);
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);
Change the declaration of vector<bool>'s swap
as follows:
void swap(vector<bool,Alloc>&&);
Change the declaration of map's swap
as follows:
void swap(map<Key,T,Compare,Alloc>&&);
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);
Change the declaration of multimap's swap
as follows:
void swap(multimap<Key,T,Compare,Alloc>&&);
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);
Change the declaration of set's swap
as follows:
void swap(set<Key,T,Compare,Alloc>&&);
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);
Change the declaration of multiset's swap
as follows:
void swap(multiset<Key,T,Compare,Alloc>&&);
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);
Change the declaration of unordered_map's swap
as follows:
void swap(unordered_map&&);
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);
Change the declaration of unordered_multimap's swap
as follows:
void swap(unordered_multimap&&);
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);
Change the declaration of unordered_set's swap
as follows:
void swap(unordered_set&&);
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);
Change the declaration of unordered_multiset's swap
as follows:
void swap(unordered_multiset&&);
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);
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); }
reference operator*() const;
std::move(*current)
requires RandomAccessIteratorunspecified operator[](difference_type n) const;
std::move(current[n])
Change the declaration of valarray's swap
as follows:
void swap(valarray&&);
Change the declaration of valarray's swap
as follows:
void swap(valarray&&);
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);
Change the declaration of basic_ios's swap
as follows:
void swap(basic_ios&&rhs);
Modify the declaration of basic_ios's swap
prior to paragraph 21 as follows:
void swap(basic_ios&&rhs);
Change the declaration of basic_streambuf's swap
as follows:
void swap(basic_streambuf&&rhs);
Change the declaration of basic_streambuf's swap
before paragraph 4 as follows:
void swap(basic_streambuf&&rhs);
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); }
<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.Change the declaration of basic_istream's swap
as follows:
void swap(basic_istream&&rhs);
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);
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);
Change the declaration of basic_iostream's swap
as follows:
void swap(basic_iostream&&rhs);
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:
template<typename charT, typename traits, typename T> basic_istream<charT, traits>& operator>>(basic_istream<charT, traits>&& is, T& x);
is >> x
is
<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.Change the declaration of basic_ostream's swap
as follows:
void swap(basic_ostream&&rhs);
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);
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);
template<typename charT, typename traits, typename T> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&& os, const T& x);
os << x
os
Change the declaration of basic_stringbuf's swap
as follows:
void swap(basic_stringbuf&&rhs);
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);
Change the declaration of basic_istringstream's swap
as follows:
void swap(basic_istringstream&&rhs);
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);
Change the declaration of basic_ostringstream's swap
as follows:
void swap(basic_ostringstream&&rhs);
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);
Change the declaration of basic_stringstream's swap
as follows:
void swap(basic_stringstream&&rhs);
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);
Change the declaration of basic_filebuf's swap
as follows:
void swap(basic_filebuf&&rhs);
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);
Change the declaration of basic_ifstream's swap
as follows:
void swap(basic_ifstream&&rhs);
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);
Change the declaration of basic_ofstream's swap
as follows:
void swap(basic_ofstream&&rhs);
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);
Change the declaration of basic_fstream's swap
as follows:
void swap(basic_fstream&&rhs);
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);
Change the declaration of thread's swap
as follows:
void swap(thread&&);
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);
Change the declaration of thread's swap
as follows:
void swap(thread&&);
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);
Change the declaration of unique_lock's swap
as follows:
void swap(unique_lock&&u);
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);
Change the declaration of packaged_task's swap
as follows:
void swap(packaged_task&&other);