为什么删除了复制和移动构造函数的对象仍然可以传递给接受右值引用的函数?

Why can an object with deleted copy- and move-constructor still be passed to a function accepting an r-value reference?

我有以下代码,显然可以在 MSVC 和 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;
}

现在,我原以为这不会编译。 Test 的移动和复制构造函数都被删除。函数 something 只接受右值引用。但是,它确实可以编译,这是程序的输出:

Before call: 3
44
After call: 44

我能想到的将 Test 类型的对象传递给函数的唯一方法是使用左值引用或常量引用。但是 something 的定义方式,它应该只接受右值,不是吗?

这是编译器资源管理器上的代码:https://godbolt.org/z/rGKdGbsM5

右值引用和左值引用一样都是引用。它们之间的区别在于可以用来初始化它们的表达式的种类。

std::move 将左值引用转换为右值引用。它不需要类型是可移动的。如果你试图在 something 中实际移动 thing 那么你会得到错误。