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_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.
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 operator<<(A&&, char)A::operator<<(int)
A().p(); // calls A::p()&&
a.p(); // calls A::p()&
-- end example ] or, if not that, 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 >> xis<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 << xosChange 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);