自动变量初始化和 copy/move 构造函数

Automatic variable initialization and copy/move constructor

我有一个片段:

struct MyCass2 {
  MyCass2() {}

  MyCass2(MyCass2 const&) = delete;

  MyCass2(MyCass2&&) = delete;
};

int
main() {
  auto a = MyCass2();
}

这导致

main.cpp:43:8: error: call to deleted constructor of 'MyCass2'
  auto a = MyCass2();
       ^   ~~~~~~~~~
main.cpp:38:3: note: 'MyCass2' has been explicitly marked deleted here
  MyCass2(MyCass2&&) = delete;
  ^
1 error generated.

为什么我认为毕竟会有模板类型推导和直接初始化?有人可以解释一下在这种情况下自动变量初始化是如何工作的吗?

Why I thought there will be a template type deduction

auto 使用模板参数推导规则推导变量的类型。在这种情况下,类型将被推断为 MyCass2.

and a direct initialization after all?

a 不是 direct-initialized, because you used copy-initialization - 请参阅标记为 (1) 的语法。

how the automatic variable initialization work in this case?

a 是从 = 右侧的临时文件复制初始化的。但是,由于该类型既不可复制也不可移动,因此不允许进行复制初始化。

But I [defined] the move/copy constructors and neither of them was called, how is that?

默认构造函数用于初始化临时对象。复制初始化中move构造函数的调用允许为elided.

I was sure that this auto var=initializer is kind of a syntax overloading. Like with copy initialization T var=initializer, where instead of operator= a copy constructor is called.

嗯,事实并非如此。这里,auto 用于且仅用于推导类型。一旦推断出类型,表达式就完全等同于

MyCass2 a = MyCass2();
auto a = MyCass2();

使用copy/move初始化。现在,由于您声明了移动构造函数(是的,已删除的函数仍然是已声明的函数),编译器将尝试使用它来将临时对象移动到 a 中,因为它是最佳匹配。当它这样做时,它会尝试使用已删除的移动构造函数。尝试使用已删除的函数格式不正确,编译器会生成错误。

如果你想让上面的代码工作,你需要定义复制或移动构造函数。请注意,在

这样的情况下
auto a = some_named_myclass2_object;

需要定义复制构造函数,因为 some_named_myclass2_object 是一个左值,没有 std::move

就不能移动