Reputation: 467
Consider this simple class
class Foo
{
public:
Foo() = default;
Foo(const Foo &) = default;
Foo & operator=(const Foo & rhs)
{
return *this;
}
Foo & operator=(Foo && rhs) = delete;
};
Foo getFoo()
{
Foo f;
return f;
}
int main()
{
Foo f;
Foo & rf = f;
rf = getFoo(); // Use of deleted move assignment.
return 0;
}
When I compile the example above I get error: use of deleted function 'Foo& Foo::operator=(Foo&&)'
From the Copy Assignment:
If only the copy assignment is provided, all argument categories select it (as long as it takes its argument by value or as reference to const, since rvalues can bind to const references), which makes copy assignment the fallback for move assignment, when move is unavailable.
Why doesn't the compiler fallback to copy assignment when const lvalue reference can bind to rvalue and const Foo & f = getFoo();
works.
Compiler - gcc 4.7.2.
Upvotes: 15
Views: 751
Reputation: 18009
There is no fallback, the concept is called overload resolution.
The compiler performs the overload resolution and makes the decision before it checks whether the method is deleted or not. The compiler decides that the move constructor is the best choice, then it determines that this method has been deleted, hence the error.
Note 1:
delete
does not literally delete the method. If delete
is used, the method is defined as deleted, but it still can be found by the overload resolution.
From the cppreference.com documentation (emphasis mine):
... overload resolution takes place first, and the program is only ill-formed if the deleted function was selected.
In your example, the move constructor is available (from the overload resolution point of view). However, it is defined as deleted.
Note 2: If you don't want your class to have a move constructor, simply do not define it. The compiler will not generate a move constructor if you have declared one of the following: copy constructor, copy assignment operator, move assignment operator, destructor.
Upvotes: 10
Reputation: 238421
The quote is perhaps a bit misleading.
If the move assignment is not declared at all due to copy assignment being explicitly declared, then the call with an r-value will "fall back" to the copy-assignment.
But, you have declared the move assignment explicitly, and deleted it. So the declaration of the move assignment "is available", and resolves to a deleted definition.
Upvotes: 4
Reputation: 65720
The compiler is doing what you ask. You have deleted the move assignment operator, which indicates you don't want to allow assigning from rvalues. The move assignment operator will be found during overload resolution, and since it's deleted, a diagnostic is issued.
If you simply declare the copy assignment operator, then the move assignment operator will not be implicitly declared, so will not be found through overload resolution and the copy assignment operator will be called instead.
Upvotes: 8