When you write MyContainer mycontainer{std::move(myclass)}; , we must list all viable MyContainer constructors that can be called with an x ​​value of type Myclass . MyContainer has a single matching constructor that takes an argument of type Myclass . To ensure that this constructor is viable, we effectively perform overload resolution again when building Myclass with an x ​​value of type Myclass . This gives us three constructors:
Myclass(int ); // not viable: no conversion from `Myclass` to `int` Myclass(Myclass&& ); // viable Myclass(const Myclass& ) = delete; // viable
The move constructor is viable since you can bind an rvalue reference to an x ​​value. The copy constructor is viable since you can bind a const lvalue reference to something. One of the tiebreaks in overload resolution selects the smallest qualification cv. The move constructor is an rvalue reference to Myclass . The copy constructor is an lvalue reference to Myclass const - this is more of a cv qualification, so it is less preferred. Thus, we select the move constructor. This constructor is not deleted, so the call is correctly formed.
The important part here is that we are building with an xvalue of type Myclass (what std::move() does is casting to xvalue). If we were building with lvalue (i.e., just MyContainer mycontainer(myclass) ), then only the copy constructor would be viable, but it was explicitly deleted, so that the whole expression is poorly formed.
how does the compiler “remember” that it was moved if the parameter was Myclass and not Myclass&& ?
There are no memories. In both cases, we try to initialize the argument in the constructor from the x value of type Myclass . In the first case, this involves calling the Myclass move Myclass . In the latter case, this is a direct link.
Barry source share