Defining Move Special Member Functions

ISO/IEC JTC1 SC22 WG21 N3044 = 10-0034 - 2010-02-14

Bjarne Stroustrup
Lawrence Crowl

This paper revises N2987 = 09-0177 - 2009-11-08. The changes include a minor wording nit, removing the inheritance of explicitness in constructors (now core issue 992) and making the default definition of the move assignment operator ill-formed if the class has virtual bases.

This paper has editing conflicts with core issue 667.

Introduction
Findings
Proposal
Wording
    1.8 The C++ object model [intro.object]
    3.1 Declarations and definitions [basic.def]
    3.2 One definition rule [basic.def.odr]
    3.7.1 Static storage duration [basic.stc.static]
    3.7.3 Automatic storage duration [basic.stc.auto]
    3.7.4.3 Safely-derived pointers [basic.stc.dynamic.safety]
    3.8 Object lifetime [basic.life]
    3.9 Types [basic.types]
    5.1.2 Lambda expressions [expr.prim.lambda]
    5.17 Assignment and compound assignment operators [expr.ass]
    6.6.3 The return statement [stmt.return]
    7.1.5 The constexpr specifier [dcl.constexpr]
    7.3.3 The using declaration [namespace.udecl]
    8.4 Function definitions [dcl.fct.def]
    8.4.1 Explicitly-defaulted definitions [dcl.fct.def.default]
    8.4.2 Deleted definitions [dcl.fct.def.delete]
    8.5 Initializers [dcl.init]
    9 Classes [class]
    9.5 Unions [class.union]
    12 Special member functions [special]
    12.2 Temporary objects [class.temporary]
    12.3.1 Conversion by constructor [class.conv.ctor]
    12.6.1 Explicit initialization [class.expl.init]
    12.8 Copying and moving class objects [class.copy]
    12.9 Inheriting Constructors [class.inhctor]
    13.3.3.1 Implicit conversion sequences [over.best.ics]
    13.3.3.1.2 User-defined conversion sequences [over.ics.user]
    13.5.3 Assignment [over.ass]
    15.1 Throwing an exception [except.throw]
    15.4 Exception specifications [except.spec]
    17.5.1.4 Detailed Specifications [structure.specifications]
    17.5.2.2 Functions within classes [functions.within.classes]
    18.7.2.1 type_index overview [type.index.overview]
    18.8.5 Exception Propagation [propagation]
    20.1.1 Template argument requirements [utility.arg.requirements]
    20.6.2 Header <type_traits> synopsis [meta.type.synop]
    20.6.4.3 Type properties [meta.unary.prop]
    20.7.5 Class template reference_wrapper [refwrap]
    20.7.12.1.4 Placeholders [func.bind.place]
    20.8.13.2 Class template shared_ptr [util.smartptr.shared]
    20.8.13.3 Class template weak_ptr [util.smartptr.weak]
Acknowledgments

Introduction

Paper N2904 examined the generation of default copy and move operations when elements are combined into an aggregate. The proposal was discussed extensively in the July 2009 meeting, and several changes were suggested at that meeting. In addition, several changes surfaced in analysis after the meeting. This paper is the formal proposal to make move functions special.

Rather than repeat much of the arguments and analysis of N2904, we present a summary of our findings and our proposal, and then present the formal wording.

Findings

More restrictive rules for when to generate a copy would break too much existing code. The rules explored, but which no longer appear viable include:

The move operations match a subset of the expressions of the copy operations. That is, all expressions that match a move operation would match a copy operation in the absence of that move operation. So,

One suggestion in N2904, was to permit compiler to null pointers that are moved from. The idea was that doing so would help debugging of move semantics. However, doing so would break too much existing code, particularly for PODS.

The standard uses the concept of copying extensively. In most cases, the standard is adequately changed by replacing "copy" with "copy/move".

Proposal

Built-in types have a move equivalent to their copy.

A struct copy is well-formed if and only if all its bases and members have a (usable) copy.

A struct move is well-formed if and only if all its bases and members have a (usable) move.

Moves and copies can be both =default and =delete, even when not implicitly declared. They must be well-formed, though.

A struct move is implicitly declared if it is well-formed and the corresponding copy is not user-declared. So, explicitly defaulting a copy constructor will supress the move constructor. One can add the move constructor back by explicitly defaulting it. Doing otherwise would require deleting the move, which leaves a hole in the expressions.


struct no_move {
    no_move( const no_move& ) = default;
};
struct has_move {
    has_move( const has_move& ) = default;
    has_move( has_move&& ) = default;
};

Likewise, the implicit copy operation is supressed if there is a corresponding user-declared move operation.


struct no_copy {
    no_copy( no_copy&& ) = default;
};
struct has_copy {
    has_copy( const has_copy& ) = default;
    has_copy( has_copy&& ) = default;
};

Unions have implicit deleted moves if a members has a non-trivial moves. This rule is the same as for copy, and means that a user-defined union copy will not shadow a move. That is S a(x+y)would be ill-formed. For example, given two classes non_trival_copier and non_trivial_mover, that are otherwise trivial, the following happens.


union wrap_copy {
    non_trival_copier c;
};
// implicit wrap_copy::wrap_copy( const wrap_copy& ) = delete;
// declaration "wrap_copy x(y)" is ill-formed
// because of delete;
// declaration "wrap_copy x(f());" is well-formed
// because the trival move is a better match.

union wrap_move {
    non_trivial_mover m;
};
// implicit wrap_move::wrap_move( wrap_move&& ) = delete;
// declaration "wrap_move x(f());" is ill-formed
// because of delete;
// declaration "wrap_move x(y);" is well-formed
// because the trival copy is a better match.

union wrap_both {
    non_trival_copier c;
    non_trivial_mover m;
};
// implicit wrap_both::wrap_both( const wrap_both& ) = delete;
// implicit wrap_both::wrap_both( wrap_both&& ) = delete;
// declaration "wrap_both x(y)" is ill-formed because of delete;
// declaration "wrap_both x(f());" is ill-formed because of delete;

The current copy operations may throw. If we added non-throwing implicit moves, then the throw() specification would require us to put the catch for unexpected into the generated move. That catch and its control flow inhibit the optimizer and add more code. We already have people looking for ways to turn off that catch unexpected, so adding one implicitly is likely to cause some concern.

However, throwing moves are problematic within the library, and some libary specifications prohibit throwing moves. To enable conditional definition of move operations within the library, we add an is_nothrow_constructible variadic type trait.

We also extend existing type traits for copy to move.

Finally, we redefine the library concepts for copy and move to reflect the status of change in core language.

Wording

The proposed wording is usually relative to working draft N2857. However, some wording is in sections heavily affected by the decision to defer concepts, and those sections are relative to working draft N2723. Those sections are so marked.

1.8 The C++ object model [intro.object]

Edit paragraph 5 as follows.

Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size. An object of trivially copyable, trivially movable, or standard-layout type (3.9) shall occupy contiguous bytes of storage.

3.1 Declarations and definitions [basic.def]

Edit paragraph 3 as follows.

[Note: in some circumstances, C++ implementations implicitly define the default constructor (12.1), copy constructor (12.8), move constructor ([class.copy]), copy assignment operator (12.8), move assignment operator ([class.copy]), or destructor (12.4) member functions. end note] [Example: given


#include <string>
struct C {
    std::string s; // std::string as in (Clause 21)
};
int main() {
    C a;
    C b = a;
    C c = std::string("hello");
    b = a;
    b = std::string("world");
}

the implementation may implicitly define functions to make the definition of C equivalent to


struct C {
    std::string s;
    C(): s() { }
    C(const C& x): s(x.s) { }
    C(C&& x): s(static_cast<std::string&&>(x.s)) { }
        // : s(std::move(x.s)) { }
    C& operator=(const C& x) { s = x.s; return *this; }
    C& operator=(C&& x) {
        s = static_cast<std::string&&>(x.s); return *this; }
        // { s = std::move(x.s); return *this; }
    ~C() { }
};

end example] end note]

3.2 One definition rule [basic.def.odr]

Edit paragraph 2 as follows.

An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. An object or non-overloaded function whose name appears as a potentially-evaluated expression is used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied. A virtual member function is used if it is not pure. An overloaded function is used if it is selected by overload resolution when referred to from a potentially-evaluated expression. [Note: this covers calls to named functions (5.2.2), operator overloading (Clause 13), user-defined conversions (12.3.2), allocation function for placement new (5.3.4), as well as non-default initialization (8.5). A copy constructor or move constructor is used even if the call is actually elided by the implementation. —end note] An allocation or deallocation function for a class is used by a new expression appearing in a potentially-evaluated expression as specified in 5.3.4 and 12.5. A deallocation function for a class is used by a delete expression appearing in a potentially-evaluated expression as specified in 5.3.5 and 12.5. A non-placement allocation or deallocation function for a class is used by the definition of a constructor of that class. A non-placement deallocation function for a class is used by the definition of the destructor of that class, or by being selected by the lookup at the point of definition of a virtual destructor (12.4). [Footnote: An implementation is not required to call allocation and deallocation functions from constructors or destructors; however, this is a permissible implementation technique. —end footnote] A copy-assignment function for a class is used by an implicitly-defined copy-assignment function for another class as specified in 12.8. A move-assignment function for a class is used by an implicitly-defined move-assignment function for another class as specified in [class.copy]. A default constructor for a class is used by default initialization or value initialization as specified in 8.5. A constructor for a class is used as specified in 8.5. A destructor for a class is used as specified in 12.4.

3.7.1 Static storage duration [basic.stc.static]

Edit paragraph 2 as follows.

If an object of static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in 12.8.

3.7.3 Automatic storage duration [basic.stc.auto]

Edit paragraph 3 as follows.

If a named automatic object has initialization or a destructor with side effects, it shall not be destroyed before the end of its block, nor shall it be eliminated as an optimization even if it appears to be unused, except that a class object or its copy/move may be eliminated as specified in 12.8.

3.7.4.3 Safely-derived pointers [basic.stc.dynamic.safety]

Edit within paragraph 2 as follows.

....

....

Edit within paragraph 3 as follows.

....

....

3.8 Object lifetime [basic.life]

Edit within paragraph 1 as follows.

The lifetime of an object is a runtime property of the object. An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor. [Note: initialization by a trivial copy/move constructor is non-trivial initialization. —end note] The lifetime of an object of type T begins when: ....

3.9 Types [basic.types]

Edit within paragraph 2 as follows.

For any object (other than a base-class subobject) of trivially copyable or trivially movable type T, whether or not the object holds a valid value of type T, the underlying bytes (1.7) making up the object can be copied into an array of char or unsigned char. [Footnote: By using, for example, the library functions (17.6.1.2) std::memcpy or std::memmove. —end footnote] If the content of the array of char or unsigned char is copied back into the object, the object shall subsequently hold its original value. ....

Edit paragraph 3 as follows.

For any trivially copyable or trivially movable type T, if two pointers to T point to distinct T objects obj1 and obj2, where neither obj1 nor obj2 is a base-class subobject, if the value of obj1 is copied into obj2, using the std::memcpy library function, obj2 shall subsequently hold the same value as obj1. [Example:


T* t1p;
T* t2p; // provided that t2p points to an initialized object ...
std::memcpy(t1p, t2p, sizeof(T)); // at this point,
// every subobject of trivially copyable 
// or trivially movable type in *t1p
// in *t1p contains the same value
// as the corresponding subobject in *t2p

end example]

Edit paragraph 4 as follows.

The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T). The value representation of an object is the set of bits that hold the value of type T. For trivially copyable or trivially movable types, the value representation is a set of bits in the object representation that determines a value, which is one discrete element of an implementation-defined set of values. [Footnote: The intent is that the memory model of C++ is compatible with that of ISO/IEC 9899 Programming Language C. —end footnote]

Edit paragraph 10 as follows.

Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2), and std::nullptr_t, and cv-qualified versions of these types (3.9.3) are collectively called scalar types. Scalar types, POD classes (Clause 9), arrays of such types and cv-qualified cv-qualified versions of these types (3.9.3) are collectively called POD types. Scalar types, trivially copyable class types (Clause 9), arrays of such types, and cv-qualified versions of these types (3.9.3) are collectively called trivially copyable types. Scalar types, trivially movable class types (Clause 9), arrays of such types, and cv-qualified versions of these types (3.9.3) are collectively called trivially movable types. Scalar types, trivial class types (Clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called trivial types. Scalar types, standard-layout class types (Clause 9), arrays of such types and cv-qualified versions of these types (3.9.3) are collectively called standard-layout types.

Edit paragraph 12 as follows. Note that literal types continue to not require a trivial move constructor.

A type is a literal type if it is:

5.1.2 Lambda expressions [expr.prim.lambda]

Note that this wording comes from N2927, which has been adopted but which has not yet appeared in a working draft.

Edit within paragraph 3 as follows.

.... An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing:

An implementation shall not add members of rvalue reference type to the closure type.

Edit paragraph 18 as follows.

The closure type associated with a lambda-expression has a deleted ([dcl.fct.def.delete]) default constructor, a deleted move assignment operator, and a deleted copy assignment operator. It has an implicitly-declared copy constructor and may have an implicitly-declared move constructor (_class.copy_ 12.8). [Note: The copy/move constructor is implicitly defined in the same way as any other implicitly declared copy/move constructor would be implicitly defined. —end note]

Delete paragraph 19.

The closure type C associated with a lambda-expression has an additional public inline constructor with a single parameter of type C&&. Given an argument object x, this constructor initializes each non-static data member m of *this as follows:

[Note: The notations are for exposition only; the members of a closure type are unnamed and std::move need not be called. —end note]

Note that paragraph 21 is unchanged because named variables are not moved.

When the lambda-expression is evaluated, the entities that are captured by copy are used to direct-initialize each corresponding non-static data member of the resulting closure object. (For array members, the array elements are direct-initialized in increasing subscript order.) These initializations are performed in the (unspecified) order in which the non-static data members are declared. [Note: This ensures that the destructions will occur in the reverse order of the constructions. —end note]

5.17 Assignment and compound assignment operators [expr.ass]

Edit paragraph 4 as follows.

If the left operand is of class type, the class shall be complete. Assignment to objects of a class is defined by the copy/move assignment operator (12.8, 13.5.3).

6.6.3 The return statement [stmt.return]

Edit paragraph 2 as follows.

A return statement without an expression can be used only in functions that do not return a value, that is, a function with the return type void, a constructor (12.1), or a destructor (12.4). A return statement with an expression of non-void type can be used only in functions returning a value; the value of the expression is returned to the caller of the function. The expression is implicitly converted to the return type of the function in which it appears. A return statement can involve the construction and copy or move of a temporary object (12.2). [Note: A copy or move operation associated with a return statement may be elided or considered as an rvalue for the purpose of overload resolution in selecting a constructor (12.8). —end note] A return statement with a braced-init-list initializes the object or reference to be returned from the function by copy-list-initialization (8.5.4) from the specified initializer list. [Example:


std::pair<std::string,int> f(const char* p, int x) {
    return {p,x};
}

end example] Flowing off the end of a function is equivalent to a return with no value; this results in undefined behavior in a value-returning function.

7.1.5 The constexpr specifier [dcl.constexpr]

Edit within paragraph 4 as follows.

.... A trivial copy/move constructor is also a constexpr constructor. ....

7.3.3 The using declaration [namespace.udecl]

Edit paragraph 4 follows.

[Note: Since destructors do not have names, a using-declaration cannot refer to a destructor for a base class. Since specializations of member templates for conversion functions are not found by name lookup, they are not considered when a using-declaration specifies a conversion function (14.6.2). —end note] If an assignment operator brought from a base class into a derived class scope has the signature of a copy-assignment copy/move assignment operator for the derived class (12.8), the using-declaration does not by itself suppress the implicit declaration of the derived class copy-assignment operator; the copy-assignment copy/move assignment operator from the base class is hidden or overridden by the implicitly-declared copy-assignment copy/move assignment operator of the derived class, as described below.

8.4 Function definitions [dcl.fct.def]

End the section after paragraph 8. The intent is to make defaulted and deleted definitions have their own section for citations.

8.4.1 Explicitly-defaulted definitions [dcl.fct.def.default]

Add a new section comprising paragraph 9 of the old 8.4 Function definitions [dcl.fct.def].

Split the paragraph into three paragraphs, with the first paragraph containing the introductory sentence, the second paragraph containing the special member discussion, and the third paragraph containing the note and example. The intent is to structure the discussion better for citations.

Edit the resulting second paragraph as follows.

Only special Special member functions may be explicitly defaulted, and the implementation shall define them as if they had implicit definitions (12.1, 12.4, 12.8). A special member function that would be implicitly defined as deleted shall not be explicitly defaulted. A special member function is user-provided if it is user-declared and not explicitly defaulted on its first declaration. A user-provided explicitly-defaulted function is defined at the point where it is explicitly defaulted.

Edit the resulting third paragraph as follows.

[Example:


struct trivial {
    trivial() = default;
    trivial(const trivial&) = default;
    trivial(trivial&&) = default;
    trivial& operator =(const trivial&) = default;
    trivial& operator =(trivial&&) = default;
    ~trivial() = default;
};

struct nontrivial1 {
    nontrivial1();
};
nontrivial1::nontrivial1() = default;         // not inline

struct nontrivial2 {
    nontrivial2();
};
inline nontrivial2::nontrivial2() = default;  // not first declaration

struct nontrivial3 {
    virtual ~nontrivial3() = 0;               // virtual
};
inline nontrivial3::~nontrivial3() = default; // not first declaration

end example]

8.4.2 Deleted definitions [dcl.fct.def.delete]

Add a new section comprising paragraph 10 of the old 8.4 Function definitions [dcl.fct.def]. Split that paragraph as follows. The intent is to structure the section better for citations.

The first paragraph comprises the introductory text. It will be as follows.

A function definition of the form:

decl-specifier-seqopt attribute-specifieropt declarator = delete ;

is called a deleted definition. A function with a deleted definition is also called a deleted function.

The second paragraph comprises the explanatory text. It will be as follows.

A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [Note: this includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function. It applies even for references in expressions that are not potentially-evaluated. If a function is overloaded, it is referenced only if the function is selected by overload resolution. —end note]

The third paragraph comprises the primary examples. Edit it as follows.

[Example: One can enforce non-default initialization and non-integral initialization with


struct sometype {
    sometype() = delete;              // redundant, but legal
    sometype(std::intmax_t) = delete;
    sometype(double);
};

end example] [Example: One can prevent use of a class in certain new expressions by using deleted definitions of a user-declared operator new for that class.


struct sometype {
    void *operator new(std::size_t) = delete;
    void *operator new[](std::size_t) = delete;
};
sometype *p = new sometype;    // error, deleted class operator new
sometype *p *q = new sometype[3]; // error, deleted class operator new[]

end example] [Example: One can make a class uncopyable, i.e. move-only, by using deleted definitions of the copy constructor and copy-assignment operator, and then providing defaulted definitions of the move constructor and the move assignment operator.


struct moveonly {
    moveonly() = default;
    moveonly(const moveonly&) = delete;
    moveonly(moveonly&&) = default;
    moveonly& operator=(const moveonly&) = delete;
    moveonly& operator=(moveonly&&) = default;
    ~moveonly() = default;
};
moveonly *p;
moveonly q(*p); // error, deleted copy constructor

end example]

The fourth paragraph comprises restrictive clauses.

A deleted function is implicitly inline. [Note: the one-definition rule (3.2) applies to deleted definitions. —end note] A deleted definition of a function shall be the first declaration of the function. [Example:


struct sometype {
    sometype();
};
sometype::sometype() = delete; // ill-formed; not first declaration

end example]

8.5 Initializers [dcl.init]

Edit paragraph 14 as follows.

The initialization that occurs in the form


T x = a;

as well as in argument passing, function return, throwing an exception (15.1), handling an exception (15.3), and aggregate member initialization (8.5.1) is called copy-initialization copy initialization. [Note: The copy initialization may invoke a move ([class.copy]). —end note]

9 Classes [class]

Edit paragraph 3 as follows.

Complete objects and member subobjects of class type shall have nonzero size. [Footnote: Base class subobjects are not so constrained. —end footnote] [Note: class objects can be assigned, passed as arguments to functions, and returned by functions (except objects of classes for which copying or moving has been restricted; see 12.8). Other plausible operators, such as equality comparison, can be defined by the user; see 13.5. —end note]

Edit paragraph 6 as follows.

A trivially copyable class is a class that:

A trivially movable class is a class that:

[Note: A class may not have a move constructor or a move assignment operator ([class.copy]), in which case it is neither trivially movable nor non-trivially movable. —end note] A trivial class is a class that has a trivial default constructor (12.1) and is trivially copyable. [Note: in particular, a trivially copyable, trivially movable, or trivial class does not have virtual functions or virtual base classes. —end note]

9.5 Unions [class.union]

Split and edit paragraph 1 as follows. The first part of paragraph 1 remains paragraph 1. The intent is to structure the discussion better for citations.

In a union, at most one of the data members can be active at any time, that is, the value of at most one of the data members can be stored in a union at any time. [Note: one special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if an object of this standard-layout union type contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of standard-layout struct members; see 9.2. —end note] The size of a union is sufficient to contain the largest of its data members. Each data member is allocated as if it were the sole member of a struct.

The second part of paragraph 1 becomes a new paragraph. Edit that paragraph as follows. Note that non-movable classes may still be copyable. Note the lone added comma after "reference type".

A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes. A union shall not be used as a base class. If a union contains a non-static data member of reference type, the program is ill-formed. [Note: if any non-static data member of a union has a non-trivial default constructor (12.1), copy constructor (12.8), move constructor (12.8), copy assignment operator (12.8), move assignment operator (12.8), or destructor (12.4), the corresponding member function of the union must be user-provided or it will be implicitly deleted ([dcl.fct.def.delete]) for the union. —end note]

The third part of paragraph 1, consisting of the string example, becomes a new paragraph. Edit that paragraph as follows.

[Example: Consider the following union:


union U {
    int i;
    float f;
    std::string s;
};

Since std::string (21.3) declares non-trivial versions of all of the special member functions, U will have an implicitly deleted default constructor, copy/move constructor, copy/move assignment operator, and destructor. To use U, some or all of these member functions must be user-declared user-provided. end example]

The fourth part of paragraph 1, consisting of the example changing the active member, becomes a new paragraph. Edit that paragraph as follows.

[Note: In general, one must use explicit destructor calls and placement new operators to change the active member of a union. —end note] [Example: Consider an object u of a union type U having non-static data members m of type M and n of type N. If M has a non-trivial destructor and N has a non-trivial constructor (for instance, if they declare or inherit virtual functions), the active member of u can be safely switched from m to n using the destructor and placement new operator as follows:


u.m.~M();
new (&u.n) N;

end example]

12 Special member functions [special]

Split and edit paragraph 1 as follows. This first part of paragraph 1 remains paragraph 1. The second part, about refering implicitly-defined member functions, becomes a new paragraph. The intent is to structure the discussion better for citations.

The default constructor (12.1), copy constructor and copy assignment operator (12.8), move constructor and move assignment operator ([class.copy]), and destructor (12.4) are special member functions. [Note: The implementation will implicitly declare these member functions for some class types when the program does not explicitly declare them. The implementation will implicitly define them if they are used. See 12.1, 12.4 and 12.8. —end note] Programs shall not define implicitly-declared special member functions.

Edit paragraph 2 as follows.

[Note: the special member functions affect the way objects of class type are created, copied, moved, and destroyed, and how values can be converted to values of other types. Often such special member functions are called implicitly. —end note]

Edit paragraph 9 as follows.

A copy constructor (12.8) is used to copy objects of class type. A move constructor ([class.copy]) is used to move the contents of objects of class type.

12.2 Temporary objects [class.temporary]

Merge and split existing paragraphs 1 and 2. Edit them as follows. The first part of paragraph 1 remains paragraph.

Temporaries of class type are created in various contexts: binding an rvalue to a reference (8.5.3), returning an rvalue (6.6.3), a conversion that creates an rvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1), entering a handler (15.3), and in some initializations (8.5). [Note: the lifetime of exception objects is described in 15.1. —end note] Even when the creation of the temporary object is avoided (12.8), all the semantic restrictions shall be respected as if the temporary object had been created. [Example: [Note: even if the copy/move constructor is not called, all the semantic restrictions, such as accessibility (Clause 11), shall be satisfied. end example] end note]

Take the last part, the true example, of the existing paragraph 1 and merge it into the existing paragraph 2.

[Example: Consider the following code.


class X {
public:
    X(int);
    X(const X&);
    ~X();
};

class Y {
public:
    Y(int);
    Y(Y&&);
    ~Y();
};

X f(X);
Y g(Y);

void h() {
    X a(1);
    X b = f(X(2));
    Y c = g(Y(3));
    a = f(a);
}

Here, an An implementation might use a temporary in which to construct X(2) before passing it to f() using X's copy-constructor copy constructor; alternatively, X(2) might be constructed in the space used to hold the argument. Likewise, an implementation might use a temporary in which to construct Y(3) before passing it to g() using Y's move constructor; alternatively, Y(3) might be constructed in the space used to hold the argument. Also, a temporary might be used to hold the result of f(X(2)) before copying it to b using X's copy-constructor copy constructor; alternatively, f()'s result might be constructed in b. Likewise, a temporary might be used to hold the result of g(Y(3)) before moving it to c using Y's move constructor; alternatively, g()'s result might be constructed in c. On the other hand, the expression a=f(a) requires a temporary for the result of f(a), which is then assigned to a. —end example]

12.3.1 Conversion by constructor [class.conv.ctor]

Edit paragraph 3 as follows.

A non-explicit copy-constructor copy/move constructor (12.8) is a converting constructor. An implicitly-declared copy/move constructor is not an explicit constructor; it may be called for implicit type conversions.

12.6.1 Explicit initialization [class.expl.init]

Within the example of paragraph 1, change uses of "copy" to "copy/move".

12.8 Copying and moving class objects [class.copy]

Edit the section title as above.

Edit paragraph 1 as follows.

A class object can be copied or moved in two ways, by initialization (12.1, 8.5), including for function argument passing (5.2.2) and for function value return (6.6.3), and by assignment (5.17). Conceptually, these two operations are implemented by a copy/move constructor (12.1) and copy/move assignment operator (13.5.3).

Split the existing paragraph 2 into two parts. The intent is to structure the discussion better for citations and to make room for a move specification. Edit the first part as follows. Note that the footnote is not deleted, but moved to later in the text.

A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6). [Footnote: Because a template constructor or a constructor whose first parameter is an rvalue reference is never a copy constructor, the presence of such a constructor does not suppress the implicit declaration of a copy constructor. Such constructors participate in overload resolution with other constructors, including copy constructors, and, if selected, will be used to copy an object. —end footnote] [Example: X::X(const X&) and X::X(X&,int=1) are copy constructors.


struct X {
    X(int);
    X(const X&, int = 1);
};
X a(1);    // calls X(int);
X b(a, 0); // calls X(const X&, int);
X c = b;   // calls X(const X&, int);

end example]

After the first part of the existing paragraph 2, add a new paragraph as follows.

A non-template constructor for class X is a move constructor if its first parameter is of type X&&, const X&&, volatile X&& or const volatile X&&, and either there are no other parameters or else all other parameters have default arguments (8.3.6). [Example: Y::Y(X&&) is a move constructor.


struct Y {
    Y(const Y&);
    Y(Y&&);
}; 
extern Y f(int);
Y d(f(1)); // calls Y(Y&&);
Y e = d;   // calls Y(const Y&);

end example]

Edit the second part of the existing paragraph 2 as follows.

[Note: all forms of copy/move constructor may be declared for a class. [Example:


struct X {
    X(const X&);
    X(X&);        // OK
    X(X&&);
    X(const X&&); // OK, but possibly not sensible
};

end example] —end note] [Note: if a class X only has a copy constructor with a parameter of type X&, an initializer of type const X or volatile X cannot initialize an object of type (possibly cv-qualified) X. [Example:


   struct X {
     X();   // default constructor
     X(X&); // copy constructor with a nonconst parameter
   };
   const X cx;
   X x = cx;    // error: X::X(X&) cannot copy cx into x

end example] —end note]

Split and edit paragraph 3 as follows. The first sentence remains within the paragraph.

A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv-qualified) X and either there are no other parameters or else all other parameters have default arguments.

Add a new paragraph consisting of the remainder of the existing paragraph 3 and edited as follows.

A member function template is never instantiated to perform the copy of a class object to an object of its class type. [Example:


struct S {
    template<typename T> S(T&);
    template<typename T> S(T&&);
    S();
};
S f();
const S g;
void h() {
    S a( f() ); // does not instantiate member template
                // uses the implicitly generated move constructor
    S a( g );   // does not instantiate member template
                // uses the implicitly generated copy constructor
}

end example]

Edit the existing paragraph 4 as follows.

If the class definition does not explicitly declare a copy constructor, and there is no user-declared move constructor, one is declared implicitly. Thus, for the class definition


struct X {
    X(const X&, int);
};

a copy constructor is implicitly-declared. If the user-declared constructor is later defined as


X::X(const X& x, int i =0) { /* ... */ }

then any use of X's copy constructor is ill-formed because of the ambiguity; no diagnostic is required.

Split the existing paragraph 5 into two parts, the form of copy constructors and the deleting of copy constructors. The first part remains unchanged as follows.

The implicitly-declared copy constructor for a class X will have the form


X::X(const X&)

if

Otherwise, the implicitly-declared copy constructor will have the form


X::X(X&)

After the first part of the existing paragraph 5, insert a new paragraph as follows.

The default definition of the move constructor for a class X is well-formed if and only if

If the class definition does not explicitly declare a move constructor, one will be declared implicitly if and only if

[Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that otherwise would have invoked the move constructor may instead invoke a copy constructor. —end note]

After the new paragraph above, insert a new paragraph as follows.

The implicitly-declared move constructor for class X will have the form


X::X(X&&)

Edit the second part of the existing paragraph 5 as follows.

An implicitly-declared copy/move constructor is an inline public member of its class. An implicitly-declared copy/move constructor for a class X is defined as deleted ([dcl.fct.def.delete]) if X has:

Edit the existing paragraph 6 as follows.

A copy/move constructor for class X is trivial if it is not user-provided (8.4) and if

otherwise the copy/move constructor is non-trivial.

Edit paragraph 7 as follows.

A non-user-provided copy/move constructor is implicitly defined if it is used to initialize an object of its class type from a copy of an object of its class type or of a class type derived from its class type. [Footnote: See 8.5 for more details on direct and copy initialization. —end footnote] [Note: the copy/move constructor is implicitly defined even if the implementation elided its use (12.2). —end note] A program is ill-formed if the implicitly-defined copy/move constructor is explicitly defaulted, but the corresponding implicit declaration would have been deleted.

Before the non-user-provided copy/move constructor for a class is implicitly defined, all non-user-provided copy/move constructors for its direct and virtual base classes and its non-static data members shall have been implicitly defined. [Note: an implicitly-declared copy/move constructor has an exception-specification (15.4). An explicitly-defaulted definition ([dcl.fct.def.default]) has no implicit exception-specification. —end note]

Paragraph 8 is unchanged as follows.

The implicitly-defined or explicitly-defaulted copy constructor for class X performs a memberwise copy of its subobjects. [Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note] The order of copying is the same as the order of initialization of bases and members in a user-defined constructor (see 12.6.2). Each subobject is copied in the manner appropriate to its type:

Virtual base class subobjects shall be copied only once by the implicitly-defined copy constructor (see 12.6.2).

Add a new paragraph after paragraph 8 above.

The implicitly-defined or explicitly-defaulted move constructor for a non-union class X performs a memberwise move of its subobjects. [Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note] The order of moving is the same as the order of initialization of bases and members in a user-defined constructor (see 12.6.2). Given an argument object x, each member m of reference type R is moved by initializing this->m with static_cast<R&&>(x.m). Each subobject is moved in the manner appropriate to its type:

Virtual base class subobjects shall be moved only once by the implicitly-defined move constructor (see 12.6.2).

Split the existing paragraph 10 into four paragraphs, the form part, the general part, the deleted part, and the hiding/using part. Edit the first form part as follows.

If the class definition does not explicitly declare a copy assignment operator, and there is no user-declared move assignment operator, one is declared implicitly. The implicitly-declared copy assignment operator for a class X will have the form


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

if

Otherwise, the implicitly-declared copy assignment operator will have the form


X& X::operator=(X&)

After the first form part, add a new paragraph as follows.

A user-declared move assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X&&, const X&&, volatile X&& or const volatile X&&. [Note: an overloaded assignment operator must be declared to have only one parameter; see 13.5.3. —end note] [Note: more than one form of move assignment operator may be declared for a class. —end note]

After the above new paragraph, add a new paragraph as follows.

The default definition of the move assignment operator for a class X is well-formed if an only if:

If the class definition does not explicitly declare a move assignment operator, one will be declared implicitly if and only if

[Example: The class definition


struct S {
    int a;
    S& operator=( const S& ) = default;
};

will not have a default move assignment operator implicitly declared because the copy assignment operator has been user-declared. The move assignment operator may be explicitly defaulted.


struct S {
    int a;
    S& operator=( const S& ) = default;
    S& operator=( S&& ) = default;
};

end cxample]

After the above new paragraph, add a new paragraph as follows.

The implicitly-declared move assignment operator for a class X will have the form


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

Edit the second part of the existing paragraph 10 into a new paragraph as follows.

The implicitly-declared copy/move assignment operator for class X has the return type X&; it returns the object for which the assignment operator is invoked, that is, the object assigned to. An implicitly-declared copy/move assignment operator is an inline public member of its class.

Edit the third part of the existing paragraph 10 into a new paragraph as follows.

An implicitly-declared copy/move assignment operator for class X is defined as deleted if X has:

Edit the fourth part of the existing paragraph 10 into a new paragraph as follows.

Because a copy/move assignment operator is implicitly declared for a class if not declared by the user, a base class copy/move assignment operator is always hidden by the copy corresponding assignment operator of a derived class (13.5.3). A using-declaration (7.3.3) that brings in from a base class an assignment operator with a parameter type that could be that of a copy-assignment copy/move assignment operator for the derived class is not considered an explicit declaration of such a copy-assignment an operator and does not suppress the implicit declaration of the derived class copy-assignment operator; the operator introduced by the using-declaration is hidden by the implicitly-declared copy-assignment operator in the derived class.

Edit paragraph 11 as follows.

A copy/move assignment operator for class X is trivial if it is not user-provided and if

otherwise the copy/move assignment operator is non-trivial.

Edit paragraph 12 as follows.

A non-user-provided copy/move assignment operator is implicitly defined when an object of its class type is assigned a value of its class type or a value of a class type derived from its class type. A program is ill-formed if the implicitly-defined copy/move assignment operator is explicitly defaulted, but the corresponding implicit declaration would have been deleted. Before the non-user-provided copy/move assignment operator for a class is implicitly defined, all non-user-provided copy assignment operators for its direct base classes and its non-static data members shall have been implicitly defined. [Note: an implicitly-declared copy/move assignment operator has an exception-specification (15.4). An explicitly-defaulted definition has no implicit exception-specification. —end note]

Edit paragraph 13 as follows.

The implicitly-defined or explicitly-defaulted copy assignment operator for class X performs memberwise copy assignment of its subobjects. The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition. Each subobject is assigned in the manner appropriate to its type:

It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined or explicitly-defaulted copy assignment operator. [Example:


struct  V { };
struct  A : virtual V { };
struct  B : virtual V { };
struct  C : B, A { };

It is unspecified whether the virtual base class subobject V is assigned twice by the implicitly-defined copy assignment operator for C. —end example]

Add a new paragraph after paragraph 13 as follows.

The implicitly-defined or explicitly-defaulted move assignment operator for a non-union class X performs memberwise assignment of its subobjects. The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition. Each subobject is assigned in the manner appropriate to its type:

A non-trivial move assignment operator shall be invoked exactly once for each virtual base subobject.

Edit paragraph 14 as follows.

A program is ill-formed if the copy/move constructor or the copy/move assignment operator for an object is implicitly used and the special member function is not accessible (Clause 11). [Note: Copying/moving one object into another using the copy/move constructor or the copy/move assignment operator does not change the layout or size of either object. —end note]

Edit paragraph 15 as follows.

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization. [Footnote: Because only one object is destroyed instead of two, and one copy/move constructor is not executed, there is still one object destroyed for each one constructed. —end footnote] This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

[Example:


class Thing {
public:
    Thing();
    ~Thing();
    Thing(const Thing&);
};
Thing f() {
    Thing t;
    return t;
}
Thing t2 = f();

Here the criteria for elision can be combined to eliminate two calls to the copy constructor of class Thing: the copying of the local automatic object t into the temporary object for the return value of function f() and the copying of that temporary object into object t2. Effectively, the construction of the local object t can be viewed as directly initializing the global object t2, and that object's destruction will occur at program exit. Adding a move constructor to Thing has the same effect, but it is the move construction from the temporary object to t2 that is elided.end example]

Paragraph 16 is unchanged as follows.

When the criteria for elision of a copy operation are met and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note] [Example:


class Thing {
public:
    Thing();
    ~Thing();
    Thing(Thing&&);
private:
    Thing(const Thing&);
};
Thing f(bool b) {
    Thing t;
    if (b)
        throw t;     // OK: Thing(Thing&&) used (or elided) to throw t
    return t;        // OK: Thing(Thing&&) used (or elided) to return t
}
Thing t2 = f(false); // OK: Thing(Thing&&) used (or elided) to construct of t2

end example]

12.9 Inheriting Constructors [class.inhctor]

Edit paragraph 3 as follows.

For each non-template constructor in the candidate set of inherited constructors other than a constructor having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly declared with the same constructor characteristics unless there is a user-declared constructor with the same signature in the class where the using-declaration appears. Similarly, for each constructor template in the candidate set of inherited constructors, a constructor template is implicitly declared with the same constructor characteristics unless there is an equivalent user-declared constructor template (14.6.6.1) in the class where the using-declaration appears. [Note: Default arguments are not inherited. —end note]

Edit paragraph 5 as follows.

[Note: Default and copy/move constructors may be implicitly declared as specified in 12.1 and 12.8. —end note]

Edit paragraph 6 as follows.

[Example:


struct B1 {
    B1(int);
};

struct B2 {
    B2(int = 13, int = 42);
};

struct D1 : B1 {
    using B1::B1;
};

struct D2 : B2 {
    using B2::B2;
};

The candidate set of inherited constructors in D1 for B1 is

The set of constructors present in D1 is

The candidate set of inherited constructors in D2 for B2 is

The set of constructors present in D2 is

end example]

13.3.3.1 Implicit conversion sequences [over.best.ics]

Edit paragraph 4 as follows.

However, when considering the argument of a user-defined conversion function that is a candidate by 13.3.1.3 when invoked for the copying/moving of the temporary in the second step of a class copy-initialization, by 13.3.1.7 when passing the initializer list as a single argument or when the initializer list has exactly one element and a conversion to some class X or reference to (possibly cv-qualified) X is considered for the first parameter of a constructor of X, or by 13.3.1.4, 13.3.1.5, or 13.3.1.6 in all cases, only standard conversion sequences and ellipsis conversion sequences are allowed.

13.3.3.1.2 User-defined conversion sequences [over.ics.user]

Edit paragraph 4 as follows.

A conversion of an expression of class type to the same class type is given Exact Match rank, and a conversion of an expression of class type to a base class of that type is given Conversion rank, in spite of the fact that a copy/move constructor (i.e., a user-defined conversion function) is called for those cases.

13.5.3 Assignment [over.ass]

Paragraph 1 is unchanged. The move assignment operator does not change the hiding.

An assignment operator shall be implemented by a non-static member function with exactly one parameter. Because a copy assignment operator operator= is implicitly declared for a class if not declared by the user (12.8), a base class assignment operator is always hidden by the copy assignment operator of the derived class.

Edit paragraph 2 as follows.

Any assignment operator, even the copy/move assignment operator, can be virtual. [Note: for a derived class D with a base class B for which a virtual copy/move assignment has been declared, the copy/move assignment operator in D does not override B's virtual copy/move assignment operator. [Example:


struct B {
    virtual int operator= (int);
    virtual B& operator= (const B&);
};

struct D : B {
    virtual int operator= (int);
    virtual D& operator= (const B&);
};

D dobj1;
D dobj2;
B* bptr = &dobj1;
void f() {
    bptr->operator=(99);    //  calls D::operator=(int)
    *bptr = 99;             //  ditto
    bptr->operator=(dobj2); //  calls D::operator=(const B&)
    *bptr = dobj2;          //  ditto
    dobj1 = dobj2;          //  calls implicitly-declared
                            //  D::operator=(const D&)
}

end example] —end note]

15.1 Throwing an exception [except.throw]

Edit paragraph 5 as follows.

When the thrown object is a class object, the copy/move constructor and the destructor shall be accessible, even if the copy/move operation is elided (12.8).

15.4 Exception specifications [except.spec]

Edit paragraph 13 as follows.

An implicitly declared special member function (Clause 12) shall have an exception-specification. If f is an implicitly declared default constructor, copy constructor, move constructor, destructor, or copy assignment operator, or move assignment operator, its implicit exception-specification specifies the type-id T if and only if T is allowed by the exception-specification of a function directly invoked by f's implicit definition; f shall allow all exceptions if any function it directly invokes allows all exceptions, and f shall allow no exceptions if every function it directly invokes allows no exceptions. [Example:


struct A {
    A();
    A(const A&) throw();
    A(A&&) throw();
    ~A() throw(X);
};
struct B {
    B() throw();
    B(const B&) throw();
    B(B&&) throw(Y);
    ~B() throw(Y);
};
struct D : public A, public B {
    // Implicit declaration of D::D();
    // Implicit declaration of D::D(const D&) throw();
    // Implicit declaration of D::D(D&&) throw(Y);
    // Implicit declaration of D::~D() throw(X,Y);
};

Furthermore, if A::~A() or B::~B() were virtual, D::~D() would not be as restrictive as that of A::~A, and the program would be ill-formed since a function that overrides a virtual function from a base class shall have an exception-specification at least as restrictive as that in the base class. —end example]

17.5.1.4 Detailed Specifications [structure.specifications]

Edit paragraph 2 as follows.

Descriptions of class member functions follow the order (as appropriate): [Footnote: To save space, items that do not apply to a class are omitted. For example, if a class does not specify any comparison functions, there will be no "Comparison functions" subclause. —end footnote]

17.5.2.2 Functions within classes [functions.within.classes]

Edit paragraph 1 as follows.

For the sake of exposition, Clauses 18 through 30 and Annex D do not describe copy/move constructors, assignment operators, or (non-virtual) destructors with the same apparent semantics as those that can be generated by default (12.1, 12.4, 12.8).

18.7.2.1 type_index overview [type.index.overview]

Edit the synopsis as follows.


namespace std {
  class type_index {
  public:
     type_index(const type_info& rhs);
     bool operator==(const type_index& rhs) const;
     bool operator!=(const type_index& rhs) const;
     bool operator< (const type_index& rhs) const;
     bool operator<= (const type_index& rhs) const;
     bool operator> (const type_index& rhs) const;
     bool operator>= (const type_index& rhs) const;
     size_t hash_code() const;
     const char* name() const;
  private:
     const type_info* target;         // exposition only
     // Note that the use of a pointer here, rather than a reference,
     // means that the default copy/move constructor and assignment
     // operators will be provided and work as expected.
  };
}

18.8.5 Exception Propagation [propagation]

Edit paragraph 2 as follows. Note that we do not require exceptions to be movable.

exception_ptr shall be DefaultConstructible, CopyConstructible, CopyAssignable and EqualityComparable. exception_ptr's operations shall not throw exceptions.

Paragraph 7 is unchanged. That is, move constructors cannot throw an exception as per the general rule.

Returns: An exception_ptr object that refers to the currently handled exception (15.3) or a copy of the currently handled exception, or a null exception_ptr object if no exception is being handled. The referenced object shall remain valid at least as long as there is an exception_ptr object that refers to it. If the function needs to allocate memory and the attempt fails, it returns an exception_ptr object that refers to an instance of bad_alloc. It is unspecified whether the return values of two successive calls to current_exception refer to the same exception object. [Note: that is, it is unspecified whether current_exception creates a new copy each time it is called. —end note] If the attempt to copy the current exception object throws an exception, the function returns an exception_ptr object that refers to the thrown exception or, if this is not possible, to an instance of bad_exception. [Note: The copy constructor of the thrown exception may also fail, so the implementation is allowed to substitute a bad_exception object to avoid infinite recursion. —end note]

20.1.1 Template argument requirements [utility.arg.requirements]

The changes in this section are relative to working draft N2723.

Edit table 33 as follows.

Table 33 — MoveConstructible requirements [moveconstructible]
Expression Post-condition
T t = rv The value of t is equivalent to the value of rv before the construction.
T t = std::move(u) The value of t is equivalent to that of u before construction. Either u is unchanged or the construction shall not throw.
[Note: There is no requirement on the value of rv after the construction. —end note]

Edit table 34 as follows.

Table 34 — CopyConstructible requirements [copyconstructible]
Expression Post-condition
T t = u the The value of u is unchanged and equivalent to t.
T t = std::move(u) The value of t is equivalent to that of u before construction. Either u is unchanged or the construction shall not throw.
[Note: A type that satisfies the CopyConstructible requirements also satisfies the MoveConstructible requirements. —end note]

Edit table 35 as follows.

Table 35 — MoveAssignable requirements [moveassignable]
Expression Return type Return value Post-condition
t = rv T& t The value of t is equivalent to the value of rv before the assignment.
t = std::move(u) T& t The value of t is equivalent to that of u before construction. Either u is unchanged or the construction shall not throw.
[Note: There is no requirement on the value of rv r_value after the assignment. —end note]

Edit table 36 as follows.

Table 36 — CopyAssignable requirements [copyassignable]
Expression Return type Return value Post-condition
t = u T& t The value of t is equivalent to u, the value of u is unchanged
t = std::move(u) T& t The value of t is equivalent to that of u before assignment. Either u is unchanged or the assignment shall not throw.
[Note: A type that satisfies the CopyAssignable requirements also satisfies the MoveAssignable requirements. —end note]

20.6.2 Header <type_traits> synopsis [meta.type.synop]

Edit within the synopsis as follows.


// 20.6.4.3, type properties:
template <class T> struct is_const;
template <class T> struct is_volatile;
template <class T> struct is_trivial;
template <class T> struct is_standard_layout;
template <class T> struct is_pod;
template <class T> struct is_empty;
template <class T> struct is_polymorphic;
template <class T> struct is_abstract;
template <class T> struct has_trivial_default_constructor;
template <class T> struct has_trivial_copy_constructor;
template <class T> struct has_trivial_move_constructor;
template <class T> struct has_trivial_copy_assign;
template <class T> struct has_trivial_move_assign;
template <class T> struct has_trivial_destructor;
template <class T> struct has_nothrow_default_constructor;
template <class T> struct has_nothrow_copy_constructor;
template <class T> struct has_nothrow_move_constructor;
template <class T, class ...Args> struct is_nothrow_constructible;
template <class T> struct has_nothrow_copy_assign;
template <class T> struct has_nothrow_move_assign;
template <class T> struct has_virtual_destructor;
template <class T> struct is_signed;
template <class T> struct is_unsigned;
template <class T> struct alignment_of;
template <class T> struct rank;
template <class T, unsigned I = 0> struct extent;

20.6.4.3 Type properties [meta.unary.prop]

Edit within Table 33 as follows.

Table 33 — Type property predicates
Template Condition Preconditions
.... .... ....
template <class T> struct has_trivial_copy_constructor; T is a trivial type (3.9) or a reference type or a class type whose copy constructors (12.8) are all trivial. T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
template <class T> struct has_trivial_move_constructor; T is a trivial type (3.9) or a reference type or a class type whose move constructors (12.8) are all trivial. T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
template <class T> struct has_trivial_copy_assign; T is neither const nor a reference type, and T is a trivial type (3.9) or a class type whose copy assignment operators (12.8) are all trivial. T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
template <class T> struct has_trivial_move_assign; T is neither const nor a reference type, and T is a trivial type (3.9) or a class type whose move assignment operators (12.8) are all trivial. T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
.... .... ....
template <class T> struct has_nothrow_copy_constructor; has_trivial_copy_constructor<T >::value
is true or T is a class type whose copy constructors are all known not to throw any exceptions or T is an array of such a class type.
T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
template <class T> struct has_nothrow_move_constructor; has_trivial_move_constructor<T >::value
is true or T is a class type whose move constructors are all known not to throw any exceptions or T is an array of such a class type.
T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
template <class T> struct has_nothrow_copy_assign; T is neither const nor a reference type, and has_trivial_copy_assign<T >::value
is true or T is a class type whose copy assignment operators taking an lvalue of type T are all known not to throw any exceptions or T is an array of such a class type.
T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
template <class T> struct has_nothrow_move_assign; T is neither const nor a reference type, and has_trivial_move_assign<T >::value
is true or T is a class type whose move assignment operators taking an rvalue of type T are all known not to throw any exceptions or T is an array of such a class type.
T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
template <class T, class ...Args> struct is_nothrow_constructible;

Given the function prototype:

template <class T> typename add_rvalue_reference<T >::type create();

the predicate condition for a template specialization is_nothrow_constructible<T, Args...> shall be satisfied if and only if the following expression would be well-formed and is known not to throw an exception:

  • if sizeof...(Args) == 1 the expression static_cast<T>(create<Args>())

  • otherwise the expression T(Args)

T shall be a complete type.
.... .... ....

20.7.5 Class template reference_wrapper [refwrap]

Edit paragraph 1 as follows.

reference_wrapper<T> is a CopyConstructible and CopyAssignable wrapper around a reference to an object of type T.

20.7.12.1.4 Placeholders [func.bind.place]

Edit paragraph 1 as follows.

All placeholder types shall be DefaultConstructible and CopyConstructible, and their default constructors and copy/move constructors shall not throw exceptions. It is implementation defined whether placeholder types are CopyAssignable. CopyAssignable placeholders' copy assignment operators shall not throw exceptions.

20.8.13.2 Class template shared_ptr [util.smartptr.shared]

Edit paragraph 2 as follows.

Specializations of shared_ptr shall be CopyConstructible, CopyAssignable, and LessThanComparable, allowing their use in standard containers. Specializations of shared_ptr shall be convertible to bool, allowing their use in boolean expressions and declarations in conditions. The template parameter T of shared_ptr may be an incomplete type.

20.8.13.3 Class template weak_ptr [util.smartptr.weak]

Edit paragraph 2 as follows.

Specializations of weak_ptr shall be CopyConstructible, CopyAssignable, and LessThanComparable, allowing their use in standard containers. Specializations of weak_ptr shall be convertible to bool, allowing their use in boolean expressions and declarations in conditions. The template parameter T of weak_ptr may be an incomplete type.

Acknowledgments

Howard Hinnant provided many helpful comments on drafts of this paper.