(From messages 20571 through 20590.)
Paragraphs 11 and 23 of 12.8 [class.copy] make a defaulted move constructor and assignment operator, respectively, deleted if there is a subobject with no corresponding move function and for which the copy operation is non-trivial. This seems excessive and unnecessary. For example:
template<typename T> struct wrap { wrap() = default; #ifdef USE_DEFAULTED_MOVE wrap(wrap&&) = default; #else wrap(wrap&& w) : t(static_cast<T&&>(w.t)) { } #endif wrap(const wrap&) = default; T t; }; struct S { S(){} S(const S&){} S(S&&){} }; typedef wrap<const S> W; W get() { return W(); } // Error, if USE_DEFAULTED_MOVE is defined, else OK
In this example the defaulted move constructor of wrap is selected by overload resolution, but this move-constructor is deleted, because S has no trivial copy-constructor.
I think that we overshoot here with the delete rules: I see no problem for the defaulted move-constructor in this example. Our triviality-deduction rules already cover this case (12.8 [class.copy] paragraph 12: W::W(W&&) is not trivial) and our exception-specification rules (15.4 [except.spec] paragraph 14) already correctly deduce a noexcept(false) specification for W::W(W&&).
It would still be OK to prevent that a move-constructor would be generated for the following example where no user-declared defaulted copy/move members are present:
template<typename T>
struct wrap_2
{
wrap_2() = default;
T t;
};
typedef wrap_2<const S> W2;
W2 get() { return W2(); } // OK, selects copy constructor
if we want. This would mean that we add a new bullet to 12.8 [class.copy] paragraph 9 and paragraph 20.
If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only ifChange 12.8¶20-23:[ 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 ] The implicitly-declared move constructor for class X will have the form
- X does not have a user-declared copy constructor,
- X does not have a user-declared copy assignment operator,
- X does not have a user-declared move assignment operator, and
- X does not have a user-declared destructor.
, andthe move constructor would not be implicitly defined as deleted.An implicitly-declared copy/move constructor is an inline public member of its class. A defaulted copy/move constructor for a class X is defined as deleted (8.4.3) if X has:X::X(X&&)A defaulted move constructor that is defined as deleted is ignored by overload resolution (13.3, 13.4). [ Note: A deleted move constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead. --end note ]
- a variant member with a non-trivial corresponding constructor and X is a union-like class,
- a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M's corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
- a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B's corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
- any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor, or
- for the copy constructor, a non-static data member of rvalue reference type.
, orfor the move constructor, a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.
If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly declared as defaulted if and only ifAdd to the end of 13.3.1:[ Example: The class definition
- X does not have a user-declared copy constructor,
- X does not have a user-declared move constructor,
- X does not have a user-declared copy assignment operator, and
- X does not have a user-declared destructor.
, andthe move assignment operator would not be implicitly defined as deleted.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; };— end example ] The implicitly-declared move assignment operator for a class X will have the formstruct S { int a; S& operator=(const S&) = default; S& operator=(S&&) = default; };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. A defaulted copy/move assignment operator for class X is defined as deleted if X has:X& X::operator=(X&&);A defaulted move assignment operator that is defined as deleted is ignored by overload resolution (13.3, 13.4).
- a variant member with a non-trivial corresponding assignment operator and X is a union-like class, or
- a non-static data member of const non-class type (or array thereof), or
- a non-static data member of reference type, or
- a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator, or
- a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator.
, orfor the move assignment operator, a non-static data member or direct base class with a type that does not have a move assignment operator and is not trivially copyable, or any direct or indirect virtual base class.
A defaulted move constructor or assignment operator (12.8) that is defined as deleted is excluded from the set of candidate functions in all contexts.