可能重复:
Why do C++11-deleted functions participate in overload resolution?
我对以下C ++ 11代码有两个问题:
#include <iostream>
using namespace std;
struct A {
A() { cout << "Default c-tor" << endl; }
A(const A&) { cout << "Copy c-tor" << endl; }
A(A&&) = delete;
};
A f()
{
A a;
return a;
}
int main()
{
A b = f();
return 0;
}
我使用gcc和clang
得到以下编译错误gcc-4.7.2(g ++ --std = c ++ 11 main.cpp):
main.cpp: In function ‘A f()’:
main.cpp:16:9: error: use of deleted function ‘A::A(A&&)’
main.cpp:8:2: error: declared here
main.cpp: In function ‘int main()’:
main.cpp:21:10: error: use of deleted function ‘A::A(A&&)’
main.cpp:8:2: error: declared here
clang-3.0(clang ++ --std = c ++ 11 main.cpp):
main.cpp:19:4: error: call to deleted constructor of 'A'
A b = f();
^ ~~~
main.cpp:8:2: note: function has been explicitly marked deleted here
A(A&&) = delete;
^
1 error generated.
提前致谢。
答案 0 :(得分:6)
A(A&&) = delete;
将其声明并定义为delete
仍然会声明它,并且不会使它完全不存在。相反,将类似(但不完全相同)声明为空和私有。像这样:
private:
A(A&&){}
事实上,这是= delete
可用之前有时用于其他运营商的技巧。
同样,它存在于查找的意义上,但调用它是不允许的,并且在C ++调用权限(几乎或所有情况下)都在其他所有事情之后完成,例如重载解析,名称查找。
标准实际上说(8.4.3)
删除的函数是隐式内联的。
并且(我发现)说删除的函数不应该参与名称查找。
另外,从8.4.3开始
隐式或明确引用已删除函数的程序, 除了宣布它之外,是不正确的。 [注意:这包括打电话 函数隐式或显式并形成指针或 指向函数的指针成员。它甚至适用于参考 无法评估的表达式。
答案 1 :(得分:2)
这是一项研究任务,但我认为声明移动构造函数表明要考虑移动构造函数。然后当它获得delete
d时,这意味着如果有移动构造函数,则可以移动对象移动到的位置。如果你想要一个没有被移动但被复制的对象,你只需要声明一个复制构造函数,你就不会提到移动构造函数。
我还没有在标准中找到声明,但是,它明确说明了上述内容,但在12.8 [class.copy]第9段中有注释支持部分上述声明:
[注意:当未隐式声明或显式提供移动构造函数时,否则将调用移动构造函数的表达式可能会调用复制构造函数。 - 后注]
答案 2 :(得分:2)
删除移动构造函数时,它不会从名称查找找到的函数集中删除它。每当您的代码通常使用移动构造函数时,您将收到错误,因为即使找到它,它也会被删除。
您的代码中有两个动作。第一个是return a
,因为当可以进行复制省略并且复制的对象由左值(a
,这里)指定时,它被视为移动。第二个是作业A b = f()
,因为f()
给你一个尚未绑定参考的临时文件。
如果您希望找到复制构造函数而不是删除的移动构造函数,那么您应该删除已删除的定义。
答案 3 :(得分:1)
来自C ++工作草案2012-11-02
8.4.3删除的定义[dcl.fct.def.delete]
...
2除了声明它之外,隐式或显式引用已删除函数的程序是不正确的。 [注意:这包括隐式或显式调用函数并形成指针或指向成员的指针 到功能。它甚至适用于未进行潜在评估的表达式中的引用。如果一个功能 重载,只有在通过重载决策选择函数时才会引用它。 - 结束说明]
...
4删除的函数是隐式内联的。
由于引用了已删除的移动构造函数,因此该程序格式错误。
不可移动类型的“用法”可能是为了防止移动,因此阻止返回本地对象。我自己没有见过这样的用法,我不知道这是否有意义,但是YMMV。