正如所料,以下内容无法编译:
class A {
public:
A() = default;
//A(A&&) = default;
A(const A&) = delete;
int x;
};
int main()
{
auto a4 = A{}; // not ok, copy constructor is deleted
auto a5 = A(); // not ok, copy constructor is deleted
return 0;
}
但是如果添加了移动构造函数,即使显式删除了复制构造函数,那么以下代码也会编译:
class A {
public:
A() = default;
A(A&&) = default;
A(const A&) = delete;
int x;
};
int main()
{
auto a4 = A{}; // now ok, even though copy constructor is deleted
auto a5 = A(); // now ok, even though copy constructor is deleted
return 0;
}
为什么不考虑删除的拷贝构造函数?
答案 0 :(得分:4)
为什么不考虑删除的拷贝构造函数?
被认为是。它没有被使用,所以它delete
d并不重要。该规则来自[dcl.fct.def.delete]:
除了声明它之外,隐式或显式引用已删除函数的程序是不正确的。 [注意: [...]如果是一个功能 重载,只有在通过重载决策选择函数时才会引用它。 [...] -end note]
auto a = A{};
上的重载决策(在这种情况下,大括号与parens相同)找到两个构造函数候选者:
A(const A&);
A(A&& );
选择哪个候选人是最好的可行性"候选人来自[over.match.best]:
鉴于这些定义,可行函数F1被定义为比另一个可行函数更好的函数 F2如果[...],然后
- [...]
- 上下文是转换函数的初始化,用于引用的直接引用绑定(13.3.1.6) 对于函数类型,F1的返回类型是相同类型的引用(即左值或右值) 引用被初始化,F2的返回类型不是
移动构造函数与参数的引用(rvalue)相同,而复制构造函数则不是。因此,它是首选并被选为最佳可行候选者。由于重载决策未选择A(const A&)
,因此我们不会引用该构造函数,因此代码很好。
如果我们实际上使用了复制构造函数(例如A a(a5)
), 实际上会尝试使用复制构造函数,这将是错误的。