11

可能重复:
为什么 C++11 删除的函数参与重载决议?

我对以下 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.
  • 如果显式删除了移动构造函数,编译器不应该使用复制构造函数吗?
  • 有谁知道“不可移动”类型的任何用途?

提前致谢。

4

4 回答 4

6
A(A&&) = delete;

声明和定义它delete仍然声明它,并没有使它完全不存在。相反,它类似于(但不完全相同)将其声明为空且私有。像这样:

private: 
  A(A&&){}

事实上,这就是以前有时用于其他运营商的技巧= delete。同样,它存在于查找的意义上,但永远不允许调用它,并且在 C++ 中,调用权限(在几乎或所有情况下)在其他所有事情之后完成,例如重载解析、名称查找。

该标准实际上说(8.4.3)

已删除的函数是隐式内联的。

并且注意到(我发现)说删除的函数不应该参与名称查找。

此外,从 8.4.3

隐式或显式引用已删除函数(而不是声明它)的程序是格式错误的。[注意:这包括隐式或显式调用函数并形成指向函数的指针或指向成员的指针。它甚至适用于未潜在评估的表达式中的引用。

于 2012-12-29T20:21:32.300 回答
2

这是一项研究任务,但我认为声明移动构造函数表明要考虑移动构造函数。当它得到deleted 时,这意味着如果有移动构造函数,对象可以移动到它们可以移动的位置。如果您想要一个不移动而是复制的对象,您只需声明一个复制构造函数,而不会提及移动构造函数。

我还没有完全找到标准中的声明,它明确说明了上述内容,但 12.8 [class.copy] 第 9 段中有注释支持上述声明的一部分:

[注意:当移动构造函数没有被隐式声明或显式提供时,否则会调用移动构造函数的表达式可能会调用复制构造函数。——尾注]

于 2012-12-29T20:21:45.533 回答
2

当您删除移动构造函数时,它不会将其从名称查找找到的函数集中删除。每当您的代码通常使用移动构造函数时,您都会收到一个错误,因为即使找到它,它也已被删除。

您的代码中有两个动作。第一个是当你return a因为复制省略是可能的并且将被复制的对象由左值(a此处,这里)指定时,它被视为移动。第二个在 assignmentA b = f()中,因为 af()给你一个尚未绑定到引用的临时。

如果您希望找到复制构造函数而不是删除的移动构造函数,则应该摆脱已删除的定义。

于 2012-12-29T20:23:53.637 回答
1

来自 C++ 工作草案 2012-11-02

8.4.3 删除的定义 [dcl.fct.def.delete]
...
2 隐式或显式引用已删除函数的程序,而不是声明它,是格式错误的。[注意:这包括隐式或显式调用函数并形成指向函数的指针或成员指针。它甚至适用于未潜在评估的表达式中的引用。如果函数被重载,则仅当函数被重载决议选择时才会被引用。— 尾注]
...
4 已删除的函数是隐式内联的。

由于引用了已删除的移动构造函数,因此程序格式错误。

不可移动类型的“用途”可能是防止移动,从而防止返回本地对象。我自己没有见过这样的用法,我不知道这是否有意义,但是 YMMV。

于 2012-12-29T20:47:11.587 回答