I have the following code, which apparently compiles in MSVC and GCC:
#include <iostream>
class Test
{
public:
Test() = default;
Test(Test const& other) = delete;
Test(Test&& other) noexcept = delete;
Test& operator=(Test const& other) = delete;
Test& operator=(Test&& other) = delete;
auto getX() -> int
{
return x;
};
auto setX(int xz) -> void
{
x = xz;
};
private:
int x = 42;
};
void something(Test&& thing) {
thing.setX(44);
std::cout << thing.getX() << std::endl;
}
int main()
{
Test a;
a.setX(3);
std::cout << "Before call: " << a.getX() << std::endl;
something(std::move(a));
std::cout << "After call: " << a.getX() << std::endl;
}
Now, I would have expected this to not compile. Both the move and the copy constructor of Test are deleted. The function something
only accepts r-value references. However, it does compile, and this is the output of the program:
Before call: 3
44
After call: 44
The only way that I could think of how it should be possible to pass an object of type Test to a function is by using an l-value reference or const ref. But the way something
is defined, it should only accept rvalues, shouldn't it?
Here is the code on compiler explorer: https://godbolt.org/z/rGKdGbsM5
rvalue references are just references just like lvalue references. The difference between them is the kind of expression that can be used to initialize them.
std::move
casts an lvalue reference to an rvalue reference. It doesn't require the type to be movable. If you try to actually move thing
in something
then you will get errors.