This question comes from issues raised by this answer.
Normally, we define copy assignment operators for type T
as T& operator=(const T&)
, and move assignment operators for type T
as T& operator=(T&&)
.
However, what happens when we use a value parameter rather than a reference?
class T
{
public:
T& operator=(T t);
};
This should make T both copy and move assignable. However, what I want to know is what are the language ramifications for T
?
Specifically:
- Does this count as a copy assignment operator for
T
, according to the specification? - Does this count as a move assignment operator for
T
, according to the specification? - Will
T
have a compiler-generated copy assignment operator? - Will
T
have a compiler-generated move assignment operator? - How does this affect traits classes like
std::is_move_assignable
?
Most of this is described in §12.8. Paragraph 17 defines what counts as user-declared copy assignment operators:
Paragraph 19 defines what counts as user-declared move assignment operators:
So, it counts as a copy assignment operator, but not as a move assignment operator.
Paragraph 18 tells when the compiler generates copy assignment operators:
Paragraph 20 tells us when the compiler generates move assignment operators:
Since the class has a user-declared copy assignment operator, neither of the implicit ones will be generated by the compiler.
std::is_copy_assignable
andstd::is_move_assignable
are described in table 49 as having the same value as, respectivelyis_assignable<T&,T const&>::value
andis_assignable<T&,T&&>::value
. That table tells us thatis_assignable<T,U>::value
istrue
when:Since both
declval<T&>() = declval<T const&>()
anddeclval<T&>() = declval<T&&>()
are well-formed for that class, it still counts as copy assignable and move assignable.As I mentioned in the comments, what's curious about all this is that, in the presence of a move constructor, that
operator=
will correctly perform moves, but technically not count as a move assignment operator. It's even stranger if the class has no copy constructor: it will have a copy assignment operator that doesn't do copies, but only moves.