Consider this simple class
Foo() = default;
Foo(const Foo &) = default;
Foo & operator=(const Foo & rhs)
Foo & operator=(Foo && rhs) = delete;
Foo & rf = f;
rf = getFoo(); // Use of deleted move assignment.
error: use of deleted function 'Foo& Foo::operator=(Foo&&)'
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.
const Foo & f = getFoo();
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.
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.