Document number: N2819=09-0009
Date: 2009-02-06
Niels Dekker <n.dekker (at) xs4all.nl>
Daniel Krügler <daniel.kruegler (at) googlemail.com>
 
 

Ref-qualifiers for assignment operators of the Standard Library


Introduction
Motivation
Implicitly declared copy-assignment operators
Assignable concepts still satisfied
Expressive power not significantly reduced
Containers of proxies
Proposed resolution
Proposed changes to requirements
Proposed explicitly-defaulted copy-assignment operators
Appendix: Assignment operators excluded from this proposal
References
Acknowledgements

Introduction

This paper serves as a supplement to LWG issue 941, Ref-qualifiers for assignment operators. The paper presents a proposed resolution to this issue, adding a ref-qualifier to over 200 assignment operators specified by the Committee Draft, N2800 [1]. The issue has been discussed before at comp.std.c++, December 2008, Ref-qualifiers for assignment operators in the Standard Library?.

Motivation

The assignment and equality operators = and == are easily confused, just because of their visual similarity, and in this case a simple typo can cause a serious bug. When the left side of an operator= is an rvalue, it's highly unlikely that the assignment was intended by the programmer:

if ( func() = value )  // Typical typo: == intended!

Built-in types don't support assignment to an rvalue, but unfortunately, a lot of types provided by the Standard Library do.

Fortunately the language now offers a syntax to prevent calling a certain member function on an rvalue: by adding a ref-qualifier (&) to the member function declaration (N2439, [2]). The operator= is explicitly mentioned as a use case of ref-qualifiers, in the section "Examples" of "Extending Move Semantics To *this (Revision 1)", by Daveed Vandevoorde and Bronek Kozicki (N1821, [3]). Bronek Kozicki also presented an example, showing that it would be beneficial to disable assignment to an rvalue within a generic context, in another paper, N1784 [4].

This paper proposes adding & ref-qualifiers to all the appropriate assignment operators in the library.

There are only a few very specific types for which it makes sense to support assigning to an rvalue. In particular, types that serve as a proxy, e.g., vector<bool>::reference, and types whose assignment operators are const-qualified (e.g., slice_array). Those types are of course excluded from this proposal.

Note that there is also a historical reason to support this proposal, as the term "lvalue" originally comes from being allowed as the left operand of an assignment (C Standard [5], footnote 53).

Implicitly declared copy-assignment operators

12.8 [class.copy]/10 specifies that an implicitly-declared copy assignment operator has one of the following two forms (depending on the definition of the class X):

X& X::operator=(const X&)
X& X::operator=(X&)

The library has over 150 classes and class templates that have an implicitly-declared copy assignment operator. Subsection Proposed explicitly-defaulted copy-assignment operators proposes to add an & ref-qualified copy assignment operator to those library types. Note that this subsection might interact with CWG issue 733, Reference qualification of copy assignment operators, submitted by Alberto Ganesh Barbati.

Assignable concepts still satisfied

After adding an & ref-qualifier to an assignment operator of an existing type, it would still satisfy the same assignable concepts as it did before. HasAssign<T,U> is satisfied when an object of type U can be assigned to an lvalue of type T. This observation is based on 14.9.2.1 [concept.map.fct]/4:
For an associated member function (or member function template) in a type X (after substitution of the concept map arguments into the associated member function or member function template), let x be an object of type cv X, where cv are the cv-qualifiers on the associated member function (or member function template). If the requirement has no ref-qualifier or if its ref-qualifier is &, x is an lvalue;

Note that Sebastian Gesemann and Douglas Gregor have been discussing the interaction between ref-qualifiers and concepts at comp.std.c++, January 2009, C++0x concepts and ref qualifiers inconsistency

Expressive power not significantly reduced

It seems highly unlikely that the proposed resolution of this issue will break any relevant use cases. However, if a user would still want to use an assignment operator with an & ref-qualifier to assign to an rvalue, she could do so by having an lvalue reference referring to the rvalue. Such an lvalue reference could be provided by the following function template:
  template <typename T>
  T& make_lvalue(T&& arg)
  {
    return arg;
  }
For example, the following would assign a literal, "text", to a temporary std::string, even when the assignment operators of std::string would have an & ref-qualifier:
  make_lvalue( std::string() ) = "text";
So the expressive power of the library will not be significantly reduced by adding & ref-qualifiers.

Containers of proxies

Howard Hinnant provided us an example, having a container of reference-like proxies. The container is assigned to an rvalue returned by tie (similar to std::tie), as follows:

#include <iostream>
#include <vector>

class my_proxy
{
   int* i_;
public:
   explicit my_proxy(int& i) : i_(&i) {}
   my_proxy& operator=(const my_proxy& i)
   {
       *i_ = *i.i_;
       return *this;
   }
   my_proxy& operator=(int i)
   {
       *i_ = i;
       return *this;
   }
   operator int() const {return *i_;}
};

std::vector<my_proxy>
tie(int& i, int& j, int& k)
{
   std::vector<my_proxy> v;
   v.push_back(my_proxy(i));
   v.push_back(my_proxy(j));
   v.push_back(my_proxy(k));
   return v;
}

int main()
{
   std::vector<my_proxy> v;
   int i = 1;
   int j = 2;
   int k = 3;
   int l = 4;
   int m = 5;
   int n = 6;
   v.push_back(my_proxy(l));
   v.push_back(my_proxy(m));
   v.push_back(my_proxy(n));
   std::cout << "i = " << i << '\n';
   std::cout << "j = " << j << '\n';
   std::cout << "k = " << k << '\n';
   tie(i, j, k) = v;
   std::cout << "i = " << i << '\n';
   std::cout << "j = " << j << '\n';
   std::cout << "k = " << k << '\n';
}
We believe that:

Proposed resolution

The proposed resolution to LWG issue 941 adds a ref-qualifier to most of the assignment operators provided by the library. It proposed to add a single ampersand (&) to over 200 places within the Committee Draft [1], according to Table 1. Note that it also has fixes of two apparent typographical errors, in 23.2.3 [forwardlist] and 24.4.1.1 [reverse.iterator] regarding the return type of operator=. The proposed resolution also includes a subsection, Proposed changes to requirements, and a subsection Proposed explicitly-defaulted copy-assignment operators.

Table 1. Proposed changes to user-declared assignment operators
SectionLine
Contents56 operator=(const basic_string<charT, traits, Allocator>&) & effects . . . . . . . . . . . . . 667
Contents57 operator=(const basic_string<charT, traits, Allocator>&&) & effects . . . . . . . . . . . . 667
18.5.2.1 [bad.alloc]bad_alloc& operator=(const bad_alloc&) & throw();
18.5.2.1 [bad.alloc]/3bad_alloc& operator=(const bad_alloc&) & throw();
18.6.3 [bad.cast]bad_cast& operator=(const bad_cast&) & throw();
18.6.3 [bad.cast]/3bad_cast& operator=(const bad_cast&) & throw();
18.6.4 [bad.typeid]bad_typeid& operator=(const bad_typeid&) & throw();
18.6.4 [bad.typeid]/3bad_typeid& operator=(const bad_typeid&) & throw();
18.7.1 [exception]exception& operator=(const exception&) & throw();
18.7.1 [exception]/3exception& operator=(const exception&) & throw();
18.7.2.1 [bad.exception]bad_exception& operator=(const bad_exception&) & throw();
18.7.2.1 [bad.exception]/3bad_exception& operator=(const bad_exception&) & throw();
18.7.6 [except.nested]nested_exception& operator=(const nested_exception&) & throw() = default;
19.4.2.2 [syserr.errcode.overview]error_code& operator=(E e) &;
19.4.2.4 [syserr.errcode.modifiers]error_code& operator=(E e) &;
19.4.3.2 [syserr.errcondition.overview]error_condition& operator=(E e) &;
19.4.3.4 [syserr.errcondition.modifiers]error_condition& operator=(E e) &;
20.2.3 [pairs]/1pair& operator=(const pair<U , V>& p) &;
20.2.3 [pairs]/1requires MoveAssignable<T1> && MoveAssignable<T2> pair& operator=(pair&& p) &;
20.2.3 [pairs]/1pair& operator=(pair<U , V>&& p) &;
20.2.3 [pairs]/10pair& operator=(const pair<U , V>& p) &;
20.2.3 [pairs]/12requires MoveAssignable<T1> && MoveAssignable<T2> pair& operator=(pair&& p) &;
20.2.3 [pairs]/14pair& operator=(pair<U, V>&& p) &;
20.6.5 [refwrap]reference_wrapper& operator=(const reference_wrapper<T>& x) &;
20.6.5.2 [refwrap.assign]reference_wrapper& operator=(const reference_wrapper<T>& x) &;
20.6.16.2 [func.wrap.func]function& operator=(const function&) &;
20.6.16.2 [func.wrap.func]function& operator=(function&&) &;
20.6.16.2 [func.wrap.func]function& operator=(nullptr_t) &;
20.6.16.2 [func.wrap.func]function& operator=(F) &;
20.6.16.2 [func.wrap.func]function& operator=(F&&) &;
20.6.16.2 [func.wrap.func]function& operator=(reference_wrapper<F>) &;
20.6.16.2.1 [func.wrap.func.con]function& operator=(const function& f) &;
20.6.16.2.1 [func.wrap.func.con]function& operator=(function&& f) &;
20.6.16.2.1 [func.wrap.func.con]function& operator=(nullptr_t) &;
20.6.16.2.1 [func.wrap.func.con]operator=(F f) &;
20.6.16.2.1 [func.wrap.func.con]function& operator=(F&& f) &;
20.6.16.2.1 [func.wrap.func.con]function& operator=(reference_wrapper<F> f) &;
20.6.18 [func.referenceclosure]reference_closure& operator=(const reference_closure&) & = default;
20.6.18 [func.referenceclosure]reference_closure& operator=(nullptr_t) &;
20.6.18.1 [func.referenceclosure.cons]reference_closure& operator=(const reference_closure& f) &
20.6.18.1 [func.referenceclosure.cons]reference_closure& operator=(nullptr_t) &;
20.7.8 [storage.iterator]/1raw_storage_iterator<OutputIterator,T>& operator=(const T& element) &;
20.7.8 [storage.iterator]/3raw_storage_iterator<OutputIterator,T>& operator=(const T& element) &;
20.7.12.2 [unique.ptr.single]unique_ptr& operator=(unique_ptr&& u) &;
20.7.12.2 [unique.ptr.single]template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) &;
20.7.12.2 [unique.ptr.single]unique_ptr& operator=(unspecified-pointer-type) &;
20.7.12.2.3 [unique.ptr.single.asgn]unique_ptr& operator=(unique_ptr&& u) &;
20.7.12.2.3 [unique.ptr.single.asgn]template <class U, class E> unique_ptr& operator=(unique_ptr<U, E>&& u) &;
20.7.12.2.3 [unique.ptr.single.asgn]unique_ptr& operator=(unspecified-pointer-type) &;
20.7.12.3 [unique.ptr.runtime]unique_ptr& operator=(unique_ptr&& u) &;
20.7.12.3 [unique.ptr.runtime]unique_ptr& operator=(unspecified-pointer-type) &;
20.7.13.2 [util.smartptr.shared]shared_ptr& operator=(const shared_ptr& r) &;
20.7.13.2 [util.smartptr.shared]template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) &;
20.7.13.2 [util.smartptr.shared]shared_ptr& operator=(shared_ptr&& r) &;
20.7.13.2 [util.smartptr.shared]template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r) &;
20.7.13.2 [util.smartptr.shared]template<class Y> shared_ptr& operator=(auto_ptr<Y>&& r) &;
20.7.13.2 [util.smartptr.shared]template <class Y, class D> shared_ptr& operator=(unique_ptr<Y, D>&& r) &;
20.7.13.2.3 [util.smartptr.shared.assign]shared_ptr& operator=(const shared_ptr& r) &;
20.7.13.2.3 [util.smartptr.shared.assign]template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) &;
20.7.13.2.3 [util.smartptr.shared.assign]template<class Y> shared_ptr& operator=(auto_ptr<Y>&& r) &;
20.7.13.2.3 [util.smartptr.shared.assign]shared_ptr& operator=(shared_ptr&& r) &;
20.7.13.2.3 [util.smartptr.shared.assign]template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r) &;
20.7.13.2.3 [util.smartptr.shared.assign]template <class Y, class D> shared_ptr& operator=(unique_ptr<Y, D>&& r) &;
20.7.13.3 [util.smartptr.weak]weak_ptr& operator=(weak_ptr const& r) &;
20.7.13.3 [util.smartptr.weak]template<class Y> weak_ptr& operator=(weak_ptr<Y> const& r) &;
20.7.13.3 [util.smartptr.weak]template<class Y> weak_ptr& operator=(shared_ptr<Y> const& r) &;
20.7.13.3.3 [util.smartptr.weak.assign]weak_ptr& operator=(const weak_ptr& r) &;
20.7.13.3.3 [util.smartptr.weak.assign]template<class Y> weak_ptr& operator=(const weak_ptr<Y>& r) &;
20.7.13.3.3 [util.smartptr.weak.assign]template<class Y> weak_ptr& operator=(const shared_ptr<Y>& r) &;
20.7.13.5 [util.smartptr.enab]enable_shared_from_this& operator=(enable_shared_from_this const&) &;
20.7.13.5 [util.smartptr.enab]enable_shared_from_this<T>& operator=(const enable_shared_from_this<T>&) &;
20.7.13.5 [util.smartptr.enab]enable_shared_from_this& operator=(enable_shared_from_this const &) & { return *this; }
20.8.3 [time.duration]duration& operator=(const duration&) & = default;
21.3 [basic.string]basic_string& operator=(const basic_string& str) &;
21.3 [basic.string]basic_string& operator=(basic_string&& str) &;
21.3 [basic.string]basic_string& operator=(const charT* s) &;
21.3 [basic.string]basic_string& operator=(charT c) &;
21.3 [basic.string]basic_string& operator=(initializer_list<charT>) &;
21.3.2 [string.cons]operator=(const basic_string<charT,traits,Allocator>& str) &;
21.3.2 [string.cons]Table 56 — operator=(const basic_string<charT, traits, Allocator>&) & effects
21.3.2 [string.cons]operator=(const basic_string<charT,traits,Allocator>&& str) &;
21.3.2 [string.cons]Table 57 — operator=(const basic_string<charT, traits, Allocator>&&) & effects
21.3.2 [string.cons]operator=(const charT* s) &;
21.3.2 [string.cons]basic_string<charT,traits,Allocator>& operator=(charT c) &;
21.3.2 [string.cons]basic_string& operator=(initializer_list<charT> il) &;
22.1.1 [locale]const locale& operator=(const locale& other) & throw();
22.1.1.2 [locale.cons]const locale& operator=(const locale& other) & throw();
23.2.2 [deque]deque<T,Alloc>& operator=(const deque<T,Alloc>& x) &;
23.2.2 [deque]deque<T,Alloc>& operator=( deque<T,Alloc>&& x) &;
23.2.2 [deque]deque& operator=(initializer_list<T>) &;
23.2.3 [forwardlist]forward_list<T,Alloc>& operator=(const forward_list<T,Alloc>& x) &;
23.2.3 [forwardlist]forward_list<T,Alloc>& operator=(forward_list<T,Alloc>&& x) &;
23.2.3 [forwardlist]forward_list<T,Alloc>& operator=(initializer_list<T>) &;
23.2.4 [list]list<T,Alloc>& operator=(const list<T,Alloc>& x) &;
23.2.4 [list]list<T,Alloc>& operator=(list<T,Alloc>&& x) &;
23.2.4 [list]list<T,Alloc>& operator=(initializer_list<T>) &;
23.2.5.1.1 [queue.defn]requires MoveAssignable<Cont> queue& operator=(queue&& q) &
23.2.5.2 [priority.queue]requires MoveAssignable<Cont> priority_queue& operator=(priority_queue&&) &;
23.2.6 [vector]vector<T,Alloc>& operator=(const vector<T,Alloc>& x) &;
23.2.6 [vector]vector<T,Alloc>& operator=(vector<T,Alloc>&& x) &;
23.2.6 [vector]vector<T,Alloc>& operator=(initializer_list<T>) &;
23.2.7 [vector.bool]vector<bool,Alloc>& operator=(const vector<bool,Alloc>& x) &;
23.2.7 [vector.bool]vector<bool,Alloc>& operator=(vector<bool,Alloc>&& x) &;
23.2.7 [vector.bool]vector<bool,Alloc>& operator=(initializer_list<bool>) &;
23.3.1 [map]map<Key,T,Compare,Alloc>& operator=(const map<Key,T,Compare,Alloc>& x) &;
23.3.1 [map]operator=(map<Key,T,Compare,Alloc>&& x) &;
23.3.1 [map]map<Key,T,Compare,Alloc>& operator=(initializer_list<value_type>) &;
23.3.2 [multimap]multimap<Key,T,Compare,Alloc>& operator=(const multimap<Key,T,Compare,Alloc>& x) &;
23.3.2 [multimap]operator=(const multimap<Key,T,Compare,Alloc>&& x) &;
23.3.2 [multimap]multimap<Key,T,Compare,Alloc>& operator=(initializer_list<value_type>) &;
23.3.3 [set]set<Key,Compare,Alloc>& operator=(const set<Key,Compare,Alloc>& x) &;
23.3.3 [set]set<Key,Compare,Alloc>& operator=(set<Key,Compare,Alloc>&& x) &;
23.3.3 [set]set<Key,Compare,Alloc>& operator=(initializer_list<value_type>) &;
23.3.4 [multiset]multiset<Key,Compare,Alloc>& operator=(const multiset<Key,Compare,Alloc>& x) &;
23.3.4 [multiset]multiset<Key,Compare,Alloc>& operator=(multiset<Key,Compare,Alloc>&& x) &;
23.3.4 [multiset]multiset<Key,Compare,Alloc>& operator=(initializer_list<value_type>) &;
23.4.1 [unord.map]unordered_map& operator=(const unordered_map&) &;
23.4.1 [unord.map]unordered_map& operator=(unordered_map&&) &;
23.4.1 [unord.map]unordered_map& operator=(initializer_list<value_type>) &;
23.4.2 [unord.multimap]unordered_multimap& operator=(const unordered_multimap&) &;
23.4.2 [unord.multimap]unordered_multimap& operator=(unordered_multimap&&) &;
23.4.2 [unord.multimap]unordered_multimap& operator=(initializer_list<value_type>) &;
23.4.3 [unord.set]unordered_set& operator=(const unordered_set&) &;
23.4.3 [unord.set]unordered_set& operator=(unordered_set&&) &;
23.4.3 [unord.set]unordered_set& operator=(initializer_list<value_type>) &;
23.4.4 [unord.multiset]unordered_multiset& operator=(const unordered_multiset&) &;
23.4.4 [unord.multiset]unordered_multiset& operator=(unordered_multiset&&) &;
23.4.4 [unord.multiset]unordered_multiset& operator=(initializer_list<value_type>) &;
24.4.1.1 [reverse.iterator]reverse_iterator& operator=(const reverse_iterator<U>& u) &;
24.4.1.2.2 [reverse.iter.op=]operator=(const reverse_iterator<U>& u) &;
24.4.2 [insert.iterators]operator* returns the insert iterator itself. The assignment operator=(const T& x) & is defined on insert iterators
24.4.2.1 [back.insert.iterator]operator=(const Cont::value_type& value) &;
24.4.2.1 [back.insert.iterator]operator=(Cont::value_type&& value) &;
24.4.2.2.2 [back.insert.iter.op=]operator=(const Cont::value_type& value) &;
24.4.2.2.2 [back.insert.iter.op=]operator=(Cont::value_type&& value) &;
24.4.2.3 [front.insert.iterator]operator=(const Cont::value_type& value) &;
24.4.2.3 [front.insert.iterator]operator=(Cont::value_type&& value) &;
24.4.2.4.2 [front.insert.iter.op=]operator=(const Cont::value_type& value) &;
24.4.2.4.2 [front.insert.iter.op=]operator=(Cont::value_type&& value) &;
24.4.2.5 [insert.iterator]operator=(const Cont::value_type& value) &;
24.4.2.5 [insert.iterator]operator=(Cont::value_type&& value) &;
24.4.2.6.2 [insert.iter.op=]operator=(const Cont::value_type& value) &;
24.4.2.6.2 [insert.iter.op=]operator=(Cont::value_type&& value) &;
24.4.3.1 [move.iterator]move_iterator& operator=(const move_iterator<U>& u) &;
24.4.3.2.2 [move.iter.op=]move_iterator& operator=(const move_iterator<U>& u) &;
24.5.2 [ostream.iterator]ostream_iterator<T,charT,traits>& operator=(const T& value) &;
24.5.2.2 [ostream.iterator.ops]ostream_iterator& operator=(const T& value) &;
24.5.4 [ostreambuf.iterator]ostreambuf_iterator& operator=(charT c) &;
24.5.4.2 [ostreambuf.iter.ops]operator=(charT c) &;
26.1 [numeric.requirements]If T is a class, it has a public assignment operator whose signature is either T& T::operator=(const T&) or T& T::operator=(T); this assignment operator may have an & ref-qualifier;
26.3.2 [complex]complex<T>& operator= (const T&) &;
26.3.2 [complex]complex& operator=(const complex&) &;
26.3.2 [complex]template<class X> complex<T>& operator= (const complex<X>&) &;
26.3.3 [complex.special]complex<float>& operator= (float) &;
26.3.3 [complex.special]complex<float>& operator=(const complex<float>&) &;
26.3.3 [complex.special]template<class X> complex<float>& operator= (const complex<X>&) &;
26.3.3 [complex.special]complex<double>& operator= (double) &;
26.3.3 [complex.special]complex<double>& operator=(const complex<double>&) &;
26.3.3 [complex.special]template<class X> complex<double>& operator= (const complex<X>&) &;
26.3.3 [complex.special]complex<long double>& operator=(const complex<long double>&) &;
26.3.3 [complex.special]complex<long double>& operator= (long double) &;
26.3.3 [complex.special]template<class X> complex<long double>& operator= (const complex<X>&) &;
26.5.2 [template.valarray]valarray<T>& operator=(const valarray<T>&) &;
26.5.2 [template.valarray]valarray<T>& operator=(valarray<T>&&) &;
26.5.2 [template.valarray]valarray& operator=(initializer_list<T>) &;
26.5.2 [template.valarray]valarray<T>& operator=(const T&) &;
26.5.2 [template.valarray]valarray<T>& operator=(const slice_array<T>&) &;
26.5.2 [template.valarray]valarray<T>& operator=(const gslice_array<T>&) &;
26.5.2 [template.valarray]valarray<T>& operator=(const mask_array<T>&) &;
26.5.2 [template.valarray]valarray<T>& operator=(const indirect_array<T>&) &;
26.5.2.2 [valarray.assign]valarray<T>& operator=(const valarray<T>&) &;
26.5.2.2 [valarray.assign]valarray<T>& operator=(valarray<T>&& v) &;
26.5.2.2 [valarray.assign]valarray& operator=(initializer_list<T> il) &;
26.5.2.2 [valarray.assign]valarray<T>& operator=(const T&) &;
26.5.2.2 [valarray.assign]valarray<T>& operator=(const slice_array<T>&) &;
26.5.2.2 [valarray.assign]valarray<T>& operator=(const gslice_array<T>&) &;
26.5.2.2 [valarray.assign]valarray<T>& operator=(const mask_array<T>&) &;
26.5.2.2 [valarray.assign]valarray<T>& operator=(const indirect_array<T>&) &;
27.5.2 [streambuf]basic_streambuf& operator=(const basic_streambuf& rhs) &;
27.5.2.3.1 [streambuf.assign]basic_streambuf& operator=(const basic_streambuf& rhs) &;
27.6.1.1 [istream]basic_istream& operator=(basic_istream&& rhs) &;
27.6.1.1.2 [istream.assign]basic_istream& operator=(basic_istream&& rhs) &;
27.6.1.5 [iostreamclass]basic_iostream& operator=(basic_iostream&& rhs) &;
27.6.1.5.3 [iostream.assign]basic_iostream& operator=(basic_iostream&& rhs) &;
27.6.2.1 [ostream]basic_ostream& operator=(basic_ostream&& rhs) &;
27.6.2.3 [ostream.assign]basic_ostream& operator=(basic_ostream&& rhs) &;
27.7.1 [stringbuf]basic_stringbuf& operator=(basic_stringbuf&& rhs) &;
27.7.1.2 [stringbuf.assign]basic_stringbuf& operator=(basic_stringbuf&& rhs) &;
27.7.2 [istringstream]basic_istringstream& operator=(basic_istringstream&& rhs) &;
27.7.2.2 [istringstream.assign]basic_istringstream& operator=(basic_istringstream&& rhs) &;
27.7.3 [ostringstream]basic_ostringstream& operator=(basic_ostringstream&& rhs) &;
27.7.3.2 [ostringstream.assign]basic_ostringstream& operator=(basic_ostringstream&& rhs) &;
27.7.4 [stringstream]basic_stringstream& operator=(basic_stringstream&& rhs) &;
27.7.5.1 [stringstream.assign]basic_stringstream& operator=(basic_stringstream&& rhs) &;
27.8.1.1 [filebuf]basic_filebuf& operator=(basic_filebuf&& rhs) &;
27.8.1.3 [filebuf.assign]basic_filebuf& operator=(basic_filebuf&& rhs) &;
27.8.1.6 [ifstream]basic_ifstream& operator=(basic_ifstream&& rhs) &;
27.8.1.8 [ifstream.assign]basic_ifstream& operator=(basic_ifstream&& rhs) &;
27.8.1.10 [ofstream]basic_ofstream& operator=(basic_ofstream&& rhs) &;
27.8.1.12 [ofstream.assign]basic_ofstream& operator=(basic_ofstream&& rhs) &;
27.8.1.14 [fstream]basic_fstream& operator=(basic_fstream&& rhs) &;
27.8.1.16 [fstream.assign]basic_fstream& operator=(basic_fstream&& rhs) &;
28.8 [re.regex]basic_regex& operator=(const basic_regex&) &;
28.8 [re.regex]basic_regex& operator=(const charT* ptr) &;
28.8 [re.regex]basic_regex& operator=(const basic_string<charT, ST, SA>& p) &;
28.8.2 [re.regex.construct]basic_regex& operator=(const basic_regex& e) &;
28.8.2 [re.regex.construct]basic_regex& operator=(const charT* ptr) &;
28.8.2 [re.regex.construct]basic_regex& operator=(const basic_string<charT, ST, SA>& p) &;
28.10 [re.results]match_results& operator=(const match_results& m) &;
28.10.1 [re.results.const]match_results& operator=(const match_results& m) &;
28.12.1 [re.regiter]regex_iterator& operator=(const regex_iterator&) &;
28.12.2 [re.tokiter]regex_token_iterator& operator=(const regex_token_iterator&) &;
29.3.1 [atomics.types.integral]bool operator=(bool) volatile &;
29.3.1 [atomics.types.integral]integral operator=(integral) volatile &;
29.3.2 [atomics.types.address]void* operator=(void*) volatile &;
29.3.3 [atomics.types.generic]T operator=(T) volatile &;
29.3.3 [atomics.types.generic]integral operator=(integral) volatile &;
29.3.3 [atomics.types.generic]T* operator=(T*) volatile &;
29.4 [atomics.types.operations]C A::operator=(C desired) volatile &;
30.2.1 [thread.thread.class]thread& operator=(thread&&) &;
30.2.1.4 [thread.thread.assign]thread& operator=(thread&& x) &;
30.3.3.2 [thread.lock.unique]unique_lock& operator=(unique_lock&& u) &;
30.3.3.2.1 [thread.lock.unique.cons]unique_lock& operator=(unique_lock&& u) &;
30.5.6 [futures.promise]promise & operator=(promise&& rhs) &;
30.5.6 [futures.promise]promise& operator=(promise&& rhs) &;
30.5.8 [futures.task]packaged_task& operator=(packaged_task&& other) &;
30.5.8 [futures.task]/6packaged_task& operator=(packaged_task&& other) &;

Proposed changes to requirements

This subsection lists the proposed changes to requirements, in order to make sure that various library types are no longer required to support assignment to an rvalue. Note that it also fixes an apparent defect in Table 80, Container requirements, that was introduced by N1858, "Rvalue Reference Recommendations for Chapter 23" [6]. An e-mail discussion with the author has revealed that the requirement to support assignment to a const rvalue was unintended.

Change 23.1.1 [container.requirements.general]/4:

In Tables 80 and 81, X denotes a container class containing objects of 
type T, a and b denote values of type X, u denotes an identifier, 
r denotes an lvalue or a const rvalue of type X, lv denotes a non-const 
lvalue of type X, and rv denotes a non-const rvalue of type X.	

Change Table 80:

Table 80 - Container requirements
Expression Return type Operational
semantics
Assertion/note
pre-/post-condition
Complexity
alv = rv; X& All existing elements
of alv are either move
assigned or destroyed
alv shall be equal to
the value that rv
had before this construction
linear
... ... ... ... ...
rlv = a X& post: rlv == a. linear

Change 23.1.3 [sequence.reqmts]/3:

In Tables 83 and 84, X denotes a sequence container class, a denotes a value of X containing elements of
type T, lv denotes a non-const lvalue of type X, ...

Change Table 83:

Table 83 - Sequence container requirements (in addition to container)
Expression Return type Assertion/note
pre-/post-condition
alv = il X& alv = X(il);
return *this;

Change 23.1.4 [associative.reqmts]/7:

In Table 85 ... r denotes an lvalue or a const rvalue of type X, lv denotes a non-const 
lvalue of type X,  rv denotes a non-const rvalue of type X, ...

Change Table 85: [The proposed change for a.emplace_hint() is an obvious editorial fix]

Table 85 - Associative container requirements (in addition to container)
Expression Return type Assertion/note
pre-/post-condition
Complexity
alv = il X& alv = X(il);
return *this;
...
... ... ... ...
a.emplace_-
hint(p,args)
iterator ... logarithmic in general, but
amortized constant if the
element is inserted right after rp

Change 23.1.5 [unord.req]/9:

In table 87: X is an unordered associative container class, a is an object of type X, lv denotes a non-const 
lvalue of type X, ...

Change Table 87: [The proposed change for the return type is an obvious editorial fix]

Table 87 - Unordered associative container requirements (in addition to container)
Expression Return type Assertion/note
pre-/post-condition
Complexity
alv = b X& ... ...

Change 27.4.3.2 [fpos.operations]/1:

Operations specified in Table 105 are permitted: In that table, 
...
- t refers to a non-const lvalue of type P,
...

Change Table 105:

Table 105 - Position type requirements
Expression Return type Operational
semantic
Assertion/note
pre-/post-condition
qt = p + o
p += o
fpos + offset qt - o == p
qt = p - o
p -= o
fpos - offset qt + o == p

Proposed explicitly-defaulted copy-assignment operators

This subsection proposes to add a user-declared copy-assignment operator, having an & ref-qualifier, and an explicitly-defaulted definition, to each of the library class types and class templates that currently have an implicitly declared copy-assignment operator. The proposed changes are listed at Table 2.

Table 2. Proposed changes for class definitions with implicit assignment operators
SectionClass (Template)Added Line to Class Body
18.2.1.1 [numeric.limits]class template numeric_limitsnumeric_limits& operator=(const numeric_limits&) & = default;
18.2.1.5 [numeric.special]/2+3template<> class numeric_limits<float>
template<> class numeric_limits<bool>
numeric_limits& operator=(const numeric_limits&) & = default;
18.5 [support.dynamic]/1struct nothrow_tnothrow_t& operator=(const nothrow_t&) & = default;
18.6 [support.rtti]/1template<> class hash<type_index>hash& operator=(const hash&) & = default;
18.6.2.1 [type.index.overview]class type_indextype_index& operator=(const type_index&) & = default;
18.8 [support.initlist]/1class template initializer_listinitializer_list& operator=(const initializer_list&) & = default;
19.1.1 [logic.error]class logic_errorlogic_error& operator=(const logic_error&) & = default;
19.1.2 [domain.error]class domain_errordomain_error& operator=(const domain_error&) & = default;
19.1.3 [invalid.argument]class invalid_argumentinvalid_argument& operator=(const invalid_argument&) & = default;
19.1.4 [length.error]class length_errorlength_error& operator=(const length_error&) & = default;
19.1.5 [out.of.range]class out_of_rangeout_of_range& operator=(const out_of_range&) & = default;
19.1.6 [runtime.error]class runtime_errorruntime_error& operator=(const runtime_error&) & = default;
19.1.7 [range.error]class range_errorrange_error& operator=(const range_error&) & = default;
19.1.8 [overflow.error]class overflow_erroroverflow_error& operator=(const overflow_error&) & = default;
19.1.9 [underflow.error]class underflow_errorunderflow_error& operator=(const underflow_error&) & = default;
19.4.2.2 [syserr.errcode.overview]/1class error_codeerror_code& operator=(const error_code&) & = default;
19.4.3.2 [syserr.errcondition.overview]/1class error_conditionerror_condition& operator=(const error_condition&) & = default;
19.4.5.1 [syserr.syserr.overview]/2class system_errorsystem_error& operator=(const system_error&) & = default;
20.2.6 [template.bitset]/1class template bitsetbitset& operator=(const bitset&) & = default;
20.3.1 [ratio.ratio]class template ratioratio& operator=(const ratio&) & = default;
20.3.2 [ratio.arithmetic]class template ratio_add
class template ratio_subtract
class template ratio_multiply
class template ratio_divide
ratio_add& operator=(const ratio_add&) & = default;
ratio_subtract& operator=(const ratio_subtract&) & = default;
ratio_multiply& operator=(const ratio_multiply&) & = default;
ratio_divide& operator=(const ratio_divide&) & = default;
20.3.3 [ratio.comparison]class template ratio_equal
class template ratio_not_equal
class template ratio_less
class template ratio_less_equal
class template ratio_greater
class template ratio_greater_equal
ratio_equal& operator=(const ratio_equal&) & = default;
ratio_not_equal& operator=(const ratio_not_equal&) & = default;
ratio_less& operator=(const ratio_less&) & = default;
ratio_less_equal& operator=(const ratio_less_equal&) & = default;
ratio_greater& operator=(const ratio_greater&) & = default;
ratio_greater_equal& operator=(const ratio_greater_equal&) & = default;
20.4.2.3 [tuple.helper]template <class... Types>
class tuple_size<tuple<Types...>>
tuple_size& operator=(const tuple_size&) & = default;
20.4.2.3 [tuple.helper]template <size_t I, class... Types>
requires True<(I < sizeof...(Types))>
class tuple_element<I, tuple<Types...>>
tuple_element& operator=(const tuple_element&) & = default;
20.5.3 [meta.help]class template integral_constantintegral_constant& operator=(const integral_constant&) & = default;
20.5.7 [meta.trans.other]/3template <class T> struct common_type<T>
template <class T, class U> struct common_type<T, U>
template <class T, class U, class... V>>
struct common_type<T, U, V...>
common_type& operator=(const common_type&) & = default;
20.6.3 [base]/1class template unary_function
class template binary_function
unary_function& operator=(const unary_function&) & = default;
binary_function& operator=(const binary_function&) & = default;
20.6.4 [func.ret]template <class Fn, class... ArgTypes>
struct result_of<Fn(ArgTypes...)>
result_of& operator=(const result_of&) & = default;
20.6.6 [identity.operation]class template identityidentity& operator=(const identity&) & = default;
20.6.7 [arithmetic.operations]class template plus
class template minus
class template multiplies
class template divides
class template modulus
class template negate
plus& operator=(const plus&) & = default;
minus& operator=(const minus&) & = default;
multiplies& operator=(const multiplies&) & = default;
divides& operator=(const divides&) & = default;
modulus& operator=(const modulus&) & = default;
negate& operator=(const negate&) & = default;
20.6.8 [comparisons]class template equal_to
class template not_equal_to
class template greater
class template less
class template greater_equal
class template less_equal
equal_to& operator=(const equal_to&) & = default;
not_equal_to& operator=(const not_equal_to&) & = default;
greater& operator=(const greater&) & = default;
less& operator=(const less&) & = default;
greater_equal& operator=(const greater_equal&) & = default;
less_equal& operator=(const less_equal&) & = default;
20.6.9 [logical.operations]class template logical_and
class template logical_or
class template logical_not
logical_and& operator=(const logical_and&) & = default;
logical_or& operator=(const logical_or&) & = default;
logical_not& operator=(const logical_not&) & = default;
20.6.10 [bitwise.operations]class template bit_and
class template bit_or
class template bit_xor
bit_and& operator=(const bit_and&) & = default;
bit_or& operator=(const bit_or&) & = default;
bit_xor& operator=(const bit_xor&) & = default;
20.6.11 [negators]class template unary_negate
class template binary_negate
unary_negate& operator=(const unary_negate&) & = default;
binary_negate& operator=(const binary_negate&) & = default;
20.6.12.1.1 [func.bind.isbind]class template is_bind_expression is_bind_expression& operator=(const is_bind_expression&) & = default;
20.6.12.1.2 [func.bind.isplace]class template is_placeholder is_placeholder& operator=(const is_placeholder&) & = default;
20.6.13 [function.pointer.adaptors]class template pointer_to_unary_function
class template pointer_to_binary_function
pointer_to_unary_function& operator=(const pointer_to_unary_function&) & = default;
pointer_to_binary_function& operator=(const pointer_to_binary_function&) & = default;
20.6.14 [member.pointer.adaptors]class template mem_fun_t
class template mem_fun1_t
class template mem_fun_ref_t
class template mem_fun1_ref_t
class template const_mem_fun_t
class template const_mem_fun1_t
class template const_mem_fun_ref_t
class template const_mem_fun1_ref_t
mem_fun_t& operator=(const mem_fun_t&) & = default;
mem_fun1_t& operator=(const mem_fun1_t&) & = default;
mem_fun_ref_t& operator=(const mem_fun_ref_t&) & = default;
mem_fun1_ref_t& operator=(const mem_fun1_ref_t&) & = default;
const_mem_fun_t& operator=(const const_mem_fun_t&) & = default;
const_mem_fun1_t& operator=(const const_mem_fun1_t&) & = default;
const_mem_fun_ref_t& operator=(const const_mem_fun_ref_t&) & = default;
const_mem_fun1_ref_t& operator=(const const_mem_fun1_ref_t&) & = default;
20.6.16.1 [func.wrap.badcall]/1class bad_function_callbad_function_call& operator=(const bad_function_call&) & = default;
20.6.17 [unord.hash]/1class template hashhash& operator=(const hash&) & = default;
20.7 [memory]/2struct allocator_arg_t
template <Allocator OuterA, Allocator InnerA>
struct is_scoped_allocator<scoped_allocator_adaptor<OuterA, InnerA>>
template <Allocator OuterA, Allocator InnerA>
struct allocator_propagate_never<scoped_allocator_adaptor<OuterA, InnerA>>
allocator_arg_t& operator=(const allocator_arg_t&) & = default;
is_scoped_allocator& operator=(const is_scoped_allocator&) & = default;
allocator_propagate_never& operator=(const allocator_propagate_never&) & = default;
20.7.1 [allocator.tag]struct allocator_arg_tallocator_arg_t& operator=(const allocator_arg_t&) & = default;
20.7.3 [allocator.element.concepts]class template is_scoped_allocatoris_scoped_allocator& operator=(const is_scoped_allocator&) & = default;
20.7.4 [allocator.propagation]class template allocator_propagate_never
class template allocator_propagate_on_copy_construction
class template allocator_propagate_on_move_assignment
class template allocator_propagate_on_copy_assignment
allocator_propagate_never& operator=(const allocator_propagate_never&) & = default;
allocator_propagate_on_copy_construction& operator=(const allocator_propagate_on_copy_construction&) & = default;
allocator_propagate_on_move_assignment& operator=(const allocator_propagate_on_move_assignment&) & = default;
allocator_propagate_on_copy_assignment& operator=(const allocator_propagate_on_copy_assignment&) & = default;
20.7.5 [allocator.propagation.map]class template allocator_propagation_mapallocator_propagation_map& operator=(const allocator_propagation_map&) & = default;
20.7.6 [default.allocator]template <> class allocator<void>
class template allocator
allocator& operator=(const allocator&) & = default;
20.7.7 [allocator.adaptor]/1template<Allocator OuterA>
class scoped_allocator_adaptor<OuterA,
unspecified allocator type>
scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) & = default;
20.7.7 [allocator.adaptor]/1template<typename OuterA,
typename InnerA>
class scoped_allocator_adaptor
scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) & = default;
20.7.12.1.1 [unique.ptr.dltr.dflt]class template default_deletedefault_delete& operator=(const default_delete&) & = default;
20.7.12.1.2 [unique.ptr.dltr.dflt1]template <class T> struct default_delete<T[]>default_delete& operator=(const default_delete&) & = default;
20.7.13.1 [util.smartptr.weakptr]class template bad_weak_ptrbad_weak_ptr& operator=(const bad_weak_ptr&) & = default;
20.7.13.4 [util.smartptr.ownerless]template <class T> struct owner_less<shared_ptr<T>>
template <class T> struct owner_less<weak_ptr<T>>
owner_less& operator=(const owner_less&) & = default;
20.8.2.1 [time.traits.is_fp]class template treat_as_floating_point treat_as_floating_point& operator=(const treat_as_floating_point&) & = default;
20.8.2.2 [time.traits.duration_values]class template duration_values duration_values& operator=(const duration_values&) & = default;
20.8.2.3 [time.traits.specializations]template <class Rep1, class Period1, class Rep2, class Period2>
struct common_type<<chrono::duration<Rep1, Period1>, chrono::duration<Rep2, Period2>>
template <class Clock, class Duration1, class Duration2>
struct common_type<<chrono:::time_point<Clock, Duration1>, chrono:::time_point<Clock, Duration2>>
common_type& operator=(const common_type&) & = default;
20.8.4 [time.point]class template time_pointtime_point& operator=(const time_point&) & = default;
20.8.5.1 [time.clock.system]/1class system_clocksystem_clock& operator=(const system_clock&) & = default;
20.8.5.2 [time.clock.monotonic]/2class monotonic_clockmonotonic_clock& operator=(const monotonic_clock&) & = default;
20.8.5.3 [time.clock.hires]/1class high_resolution_clockhigh_resolution_clock& operator=(const high_resolution_clock&) & = default;
21.1.3.1 [char.traits.specializations.char]template<> class char_traits<char>char_traits& operator=(const char_traits&) & = default;
21.1.3.2 [char.traits.specializations.char16_t]template<> class char_traits<char16_t>char_traits& operator=(const char_traits&) & = default;
21.1.3.3 [char.traits.specializations.char32_t]template<> class char_traits<char32_t>char_traits& operator=(const char_traits&) & = default;
21.1.3.4 [char.traits.specializations.wchar.t]template<> class char_traits<wchar_t>char_traits& operator=(const char_traits&) & = default;
22.1.3.2.2 [conversions.string]/2class template wstring_convertwstring_convert& operator=(const wstring_convert&) & = default;
22.2.1 [category.ctype]class ctype_basectype_base& operator=(const ctype_base&) & = default;
22.2.1.4 [locale.codecvt]class codecvt_basecodecvt_base& operator=(const codecvt_base&) & = default;
22.2.5.1 [locale.time.get]class time_basetime_base& operator=(const time_base&) & = default;
22.2.6.3 [locale.moneypunct]class money_basemoney_base& operator=(const money_base&) & = default;
22.2.7.1 [locale.messages]class messages_basemessages_base& operator=(const messages_base&) & = default;
23.2.1 [array]/3class template arrayarray& operator=(const array&) & = default;
23.2.5.1.1 [queue.defn]class template queuequeue& operator=(const queue&) & = default;
23.2.5.2 [priority.queue]class template priority_queuepriority_queue& operator=(const priority_queue&) & = default;
23.2.5.3.1 [stack.defn]class template stackstack& operator=(const stack&) & = default;
23.3.1 [map]/2class template map::value_comparevalue_compare& operator=(const value_compare&) & = default;
23.3.2 [multimap]/2class template multimap::value_comparevalue_compare& operator=(const value_compare&) & = default;
24.2 [iterator.synopsis]struct input_iterator_tag
struct output_iterator_tag
struct forward_iterator_tag
struct bidirectional_iterator_tag
struct random_access_iterator_tag
input_iterator_tag& operator=(const input_iterator_tag&) & = default;
output_iterator_tag& operator=(const output_iterator_tag&) & = default;
forward_iterator_tag& operator=(const forward_iterator_tag&) & = default;
bidirectional_iterator_tag& operator=(const bidirectional_iterator_tag&) & = default;
random_access_iterator_tag& operator=(const random_access_iterator_tag&) & = default;
24.4.2.1 [back.insert.iterator]class template back_insert_iteratorback_insert_iterator& operator=(const back_insert_iterator&) & = default;
24.4.2.3 [front.insert.iterator]class template front_insert_iteratorfront_insert_iterator& operator=(const front_insert_iterator&) & = default;
24.4.2.5 [insert.iterator]class template insert_iteratorinsert_iterator& operator=(const insert_iterator&) & = default;
24.5.1 [istream.iterator]/3class template istream_iteratoristream_iterator& operator=(const istream_iterator&) & = default;
24.5.2 [ostream.iterator]/2class template ostream_iteratorostream_iterator& operator=(const ostream_iterator&) & = default;
24.5.3 [istreambuf.iterator]class template istreambuf_iteratoristreambuf_iterator& operator=(const istreambuf_iterator&) & = default;
24.5.3.1 [istreambuf.iterator::proxy]class template istreambuf_iterator::proxyproxy& operator=(const proxy&) & = default;
24.5.4 [ostreambuf.iterator]class template ostreambuf_iteratorostreambuf_iterator& operator=(const ostreambuf_iterator&) & = default;
26.4.3.1 [rand.eng.lcong]class template linear_congruential_enginelinear_congruential_engine& operator=(const linear_congruential_engine&) & = default;
26.4.3.2 [rand.eng.mers]/3class template mersenne_twister_enginemersenne_twister_engine& operator=(const mersenne_twister_engine&) & = default;
26.4.3.3 [rand.eng.sub]/4class template subtract_with_carry_enginesubtract_with_carry_engine& operator=(const subtract_with_carry_engine&) & = default;
26.4.4.1 [rand.adapt.disc]/3class template discard_block_enginediscard_block_engine& operator=(const discard_block_engine&) & = default;
26.4.4.2 [rand.adapt.ibits]/4class template independent_bits_engineindependent_bits_engine& operator=(const independent_bits_engine&) & = default;
26.4.4.3 [rand.adapt.shuf]/3class template shuffle_order_engineshuffle_order_engine& operator=(const shuffle_order_engine&) & = default;
26.4.7.1 [rand.util.seedseq]/2class seed_seqseed_seq& operator=(const seed_seq&) & = default;
26.4.8.1.1 [rand.dist.uni.int]/1class template uniform_int_distributionuniform_int_distribution& operator=(const uniform_int_distribution&) & = default;
26.4.8.1.2 [rand.dist.uni.real]/1class template uniform_real_distributionuniform_real_distribution& operator=(const uniform_real_distribution&) & = default;
26.4.8.2.1 [rand.dist.bern.bernoulli]/1class bernoulli_distributionbernoulli_distribution& operator=(const bernoulli_distribution&) & = default;
26.4.8.2.2 [rand.dist.bern.bin]/1class template binomial_distributionbinomial_distribution& operator=(const binomial_distribution&) & = default;
26.4.8.2.3 [rand.dist.bern.geo]/1class template geometric_distributiongeometric_distribution& operator=(const geometric_distribution&) & = default;
26.4.8.2.4 [rand.dist.bern.negbin]/1class template negative_binomial_distributionnegative_binomial_distribution& operator=(const negative_binomial_distribution&) & = default;
26.4.8.3.1 [rand.dist.pois.poisson]/1class template poisson_distributionpoisson_distribution& operator=(const poisson_distribution&) & = default;
26.4.8.3.2 [rand.dist.pois.exp]/1class template exponential_distributionexponential_distribution& operator=(const exponential_distribution&) & = default;
26.4.8.3.3 [rand.dist.pois.gamma]/1class template gamma_distributiongamma_distribution& operator=(const gamma_distribution&) & = default;
26.4.8.3.4 [rand.dist.pois.weibull]/1class template weibull_distributionweibull_distribution& operator=(const weibull_distribution&) & = default;
26.4.8.3.5 [rand.dist.pois.extreme]/1class template extreme_value_distributionextreme_value_distribution& operator=(const extreme_value_distribution&) & = default;
26.4.8.4.1 [rand.dist.norm.normal]/1class template normal_distributionnormal_distribution& operator=(const normal_distribution&) & = default;
26.4.8.4.2 [rand.dist.norm.lognormal]/1class template lognormal_distributionlognormal_distribution& operator=(const lognormal_distribution&) & = default;
26.4.8.4.3 [rand.dist.norm.chisq]/1class template chi_squared_distributionchi_squared_distribution& operator=(const chi_squared_distribution&) & = default;
26.4.8.4.4 [rand.dist.norm.cauchy]/1class template cauchy_distributioncauchy_distribution& operator=(const cauchy_distribution&) & = default;
26.4.8.4.5 [rand.dist.norm.f]/1class template fisher_f_distributionfisher_f_distribution& operator=(const fisher_f_distribution&) & = default;
26.4.8.4.6 [rand.dist.norm.t]/1class template student_t_distributionstudent_t_distribution& operator=(const student_t_distribution&) & = default;
26.4.8.5.1 [rand.dist.samp.discrete]/1class template discrete_distributiondiscrete_distribution& operator=(const discrete_distribution&) & = default;
26.4.8.5.2 [rand.dist.samp.pconst]/1class template piecewise_constant_distributionpiecewise_constant_distribution& operator=(const piecewise_constant_distribution&) & = default;
26.4.8.5.3 [rand.dist.samp.genpdf]/1class template general_pdf_distributiongeneral_pdf_distribution& operator=(const general_pdf_distribution&) & = default;
26.5.4 [class.slice]class sliceslice& operator=(const slice&) & = default;
26.5.6 [class.gslice]class gslicegslice& operator=(const gslice&) & = default;
27.4.2.1.1 [ios::failure]class ios_base::failurefailure& operator=(const failure&) & = default;
27.4.2.1.6 [ios::Init]class ios_base::InitInit& operator=(const Init&) & = default;
27.4.3 [fpos]class template fposfpos& operator=(const fpos&) & = default;
28.6 [re.badexp]class regex_errorregex_error& operator=(const regex_error&) & = default;
28.7 [re.traits]class template regex_traitsregex_traits& operator=(const regex_traits&) & = default;
28.9 [re.submatch]class template sub_matchsub_match& operator=(const sub_match&) & = default;
30.2.1.1 [thread.thread.id]class thread::idid& operator=(const id&) & = default;
30.3.3 [thread.lock]/2struct defer_lock_t
struct try_to_lock_t
struct adopt_lock_t
defer_lock_t& operator=(const defer_lock_t&) & = default;
try_to_lock_t& operator=(const try_to_lock_t&) & = default;
adopt_lock_t& operator=(const adopt_lock_t&) & = default;
30.5.3 [futures.future_error]class future_errorfuture_error& operator=(const future_error&) & = default;
30.5.7 [futures.allocators]template <class R, class Alloc>
struct uses_allocator<promise<R>, Alloc>
template <class R>
struct constructible_with_allocator_prefix<promise<R>>
uses_allocator& operator=(const uses_allocator&) & = default;
constructible_with_allocator_prefix& operator=(const constructible_with_allocator_prefix&) & = default;

Change 23.2.1.1 [array.cons], as a consequence of the proposed change of [array] by Table 2:

Class array relies on the implicitly-declared special member functions (12.1, 12.4, and 12.8), and its explicitly-defaulted assignment operator (8.4, [dcl.fct.def]), to conform to the container requirements table in 23.1.

Appendix: Assignment operators excluded from this proposal

Table 3 lists the assignment operators that are excluded from this proposal. The following types are excluded:

Copy assignment operators that have a deleted definition are also excluded from this proposal. If an & ref-qualifier would be added to a deleted copy assignment operator, it would allow a library implementation to add an extra overload, having an && ref-qualifier (according to 17.6.5.5 [member.functions]/2). This is not the intention of this proposal.

Table 3. Assignment operators that are not affected by the proposal
SectionLine
20.2.6 [template.bitset]reference& operator=(bool x); // for b[i] = x;
20.2.6 [template.bitset]reference& operator=(const reference&); // for b[i] = b[j];
20.4.2 [tuple.tuple]requires CopyAssignable<Types>... tuple& operator=(const tuple&);
20.4.2 [tuple.tuple]tuple& operator=(const tuple<UTypes...>&);
20.4.2 [tuple.tuple]tuple& operator=(tuple<UTypes...>&&);
20.4.2.1 [tuple.cnstr]requires CopyAssignable<Types>... tuple& operator=(const tuple& u);
20.4.2.1 [tuple.cnstr]requires MoveAssignable<Types>... tuple& operator=(tuple&& u);
20.4.2.1 [tuple.cnstr]tuple& operator=(const tuple<UTypes...>& u);
20.4.2.1 [tuple.cnstr]tuple& operator=(tuple<UTypes...>&& u);
20.4.2.1 [tuple.cnstr]/10tuple& operator=(const pair<UTypes...>&);
20.4.2.1 [tuple.cnstr]tuple& operator=(pair<UTypes...>&&);
23.2.7 [vector.bool]reference& operator=(const bool x);
23.2.7 [vector.bool]reference& operator=(const reference& x);
26.5.5 [template.slice.array]const slice_array& operator=(const slice_array&) const;
26.5.5.1 [slice.arr.assign]const slice_array& operator=(const slice_array&) const;
26.5.7 [template.gslice.array]const gslice_array& operator=(const gslice_array&) const;
26.5.7.1 [gslice.array.assign]const gslice_array& operator=(const gslice_array&) const;
26.5.8 [template.mask.array]const mask_array& operator=(const mask_array&) const;
26.5.8.1 [mask.array.assign]const mask_array& operator=(const mask_array&) const;
26.5.9 [template.indirect.array]const indirect_array& operator=(const indirect_array&) const;
26.5.9.1 [indirect.array.assign]const indirect_array& operator=(const indirect_array&) const;
D.9.1 [auto.ptr]auto_ptr& operator=(auto_ptr&) throw();
D.9.1 [auto.ptr]template<class Y> auto_ptr& operator=(auto_ptr<Y>&) throw();
D.9.1 [auto.ptr]auto_ptr& operator=(auto_ptr_ref<X> r) throw();
D.9.1.1 [auto.ptr.cons]auto_ptr& operator=(auto_ptr& a) throw();
D.9.1.1 [auto.ptr.cons]template<class Y> auto_ptr& operator=(auto_ptr<Y>& a) throw();
D.9.1.3 [auto.ptr.conv]auto_ptr& operator=(auto_ptr_ref<X> r) throw()
18.6.1 [type.info]type_info& operator=(const type_info& rhs) = delete; // cannot be copied
19.4.1.1 [syserr.errcat.overview]error_category& operator=(const error_category&) = delete;
20.7.12.2 [unique.ptr.single]unique_ptr& operator=(const unique_ptr&) = delete;
20.7.12.2 [unique.ptr.single]template <class U, class E> unique_ptr& operator=(const unique_ptr<U, E>&) = delete;
20.7.12.3 [unique.ptr.runtime]unique_ptr& operator=(const unique_ptr&) = delete;
20.7.13.2 [util.smartptr.shared]template <class Y, class D> shared_ptr& operator=(const unique_ptr<Y, D>& r) = delete;
22.1.1.1.2 [locale.facet]void operator=(const facet&) = delete;
22.1.1.1.3 [locale.id]void operator=(const id&) = delete;
26.4.6 [rand.device]void operator=(const random_device& ) = delete;
27.4.2 [ios.base]ios_base& operator=(const ios_base&) = delete;
27.4.4 [ios]basic_ios& operator=(const basic_ios&) = delete;
27.6.1.1.3 [istream::sentry]sentry& operator=(const sentry&) = delete;
27.6.2.4 [ostream::sentry]sentry& operator=(const sentry&) = delete;
29.3.1 [atomics.types.integral]atomic_bool& operator=(const atomic_bool&) = delete;
29.3.1 [atomics.types.integral]atomic_itype& operator=(const atomic_itype &) = delete;
29.3.2 [atomics.types.address]atomic_address& operator=(const atomic_address&) = delete;
29.3.3 [atomics.types.generic]atomic& operator=(const atomic&) = delete;
29.3.3 [atomics.types.generic]atomic& operator=(const atomic&) = delete;
29.3.3 [atomics.types.generic]atomic& operator=(const atomic&) = delete;
29.5 [atomics.flag]atomic_flag& operator=(const atomic_flag&) = delete;
30.2.1 [thread.thread.class]thread& operator=(const thread&) = delete;
30.3 [thread.mutex]once_flag& operator=(const once_flag&) = delete;
30.3.1.1 [thread.mutex.class]mutex& operator=(const mutex&) = delete;
30.3.1.2 [thread.mutex.recursive]recursive_mutex& operator=(const recursive_mutex&) = delete;
30.3.2.1 [thread.timedmutex.class]timed_mutex& operator=(const timed_mutex&) = delete;
30.3.2.2 [thread.timedmutex.recursive]recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
30.3.3.1 [thread.lock.guard]lock_guard& operator=(lock_guard const&) = delete;
30.3.3.2 [thread.lock.unique]unique_lock& operator=(unique_lock const&) = delete;
30.4.1 [thread.condition.condvar]condition_variable& operator=(const condition_variable&) = delete;
30.4.2 [thread.condition.condvarany]condition_variable_any& operator=(const condition_variable_any&) = delete;
30.5.4 [futures.unique_future]unique_future& operator=(const unique_future& rhs) = delete;
30.5.5 [future.shared_future]shared_future & operator=(const shared_future& rhs) = delete;
30.5.6 [futures.promise]promise & operator=(const promise& rhs) = delete;
30.5.8 [futures.task]packaged_task& operator=(packaged_task&) = delete;

References

  1. N2800, Committee Draft, Standard for Programming Language C++, 2008-10-08
  2. Bronek Kozicki, N2439, Extending move semantics to *this (revised wording), 2007-10-05
  3. Daveed Vandevoorde and Bronek Kozicki, N1821, Extending Move Semantics To *this (Revision 1), 2005-08-24
  4. Bronek Kozicki, N1784, A proposal to add l-value member function qualifier, 2005-04-15
  5. WG14/N1124, ISO/IEC 9899 - Programming languages - C, 2005-05-06
  6. Howard E. Hinnant, N1858, Rvalue Reference Recommendations for Chapter 23, 2005-08-26

Acknowledgements

Special thanks to Alberto Ganesh Barbati, Walter E. Brown, Sebastian Gesemann, Howard Hinnant, and Bronek Kozicki for their help and feedback. Thanks very much as well to the Dutch HCC C gebruikersgroep.

Daniel Krügler works as a software developer at Bruker Daltonik, Bremen, Germany. Niels Dekker works as a scientific programmer at the Division of Image Processing (LKEB), Leiden University Medical Center, The Netherlands.