“隐式删除”构造函数=删除还是根本没有声明?

CPP*_*PPL 3 c++ deleted-functions

给出以下玩具代码:

class X
{
public:
    X() { }
    X(const X&) { }
    //X(X&&) = delete;
};

int main()
{
    X x;
    X y = std::move(x);
}
Run Code Online (Sandbox Code Playgroud)

我知道X::X(X&&)在这种情况下它被隐式删除,因为它X(const X&)作为用户声明的构造函数存在。但我对这里术语“隐式删除”的含义有点困惑:如果我们取消注释,代码的行为会有所不同,这意味着隐式删除“显式”删除X(X&&) = delete;之间存在差异。

我心中有两种不同的理解:

  • “隐式删除”意味着编译器生成一些类似于的代码X(X&&) = delete;(也就是说,编译器知道存在X(X&&)并且知道它X(X&&)被删除),但生成的代码X(X&&) = delete;在某种程度上不同于,当X y = std::move(x);尝试调用时X::X(X&&),编译器选择X(const X&)而不是报告错误。(如果X(X&&) = delete;取消注释,编译器不会选择X(const X&),会报错)

  • “隐式删除”意味着X(X&&)根本没有在类中声明,换句话说,编译器没有任何有关的信息X(X&&),因此X y = std::move(x);直接与X(const X&).

请问我的理解哪一个是正确的?


我的猜测是前者应该是正确的。因为如果我们把上面的代码改成如下:

class X
{
public:
    X() { }
    //X(const X&) { }
    X(X&&) {}
};

int main()
{
    X x;
    X y = x;
}
Run Code Online (Sandbox Code Playgroud)

我们收到一条错误消息'X::X(const X &)': attempting to reference a deleted function,这意味着编译器知道X(const X &)它何时被隐式删除。

然而,对我来说,我的后一种理解似乎是一种更直接的完成工作的方式。所以我想知道为什么我们要设计“隐式删除”的概念(这也给我一种不一致的感觉,因为“隐式删除”需要与“显式删除”有不同的行为)

Enr*_*lis 7

当您取消注释时X(X&&) = delete;,您所做的就是声明该 ctor 已删除。例如,这意味着它确实参与了重载决策,在以下情况下它会获胜X y = std::move(x);,但实际上不能使用,因为它缺少主体。

\n

请注意,这并不专门适用于(特殊或非)成员函数,而是适用于一般函数:

\n
#include<iostream>\n\n// this is akin to defining both copy and move ctor\nauto f(int) { std::cout << "int" << std::endl;}\nauto f(double) { std::cout << "double" << std::endl;}\n\n// this is akin to defining copy ctor and deleting move ctor\nauto g(int) { std::cout << "int" << std::endl;}\nauto g(double) = delete;\n\n// this is akin to defining only copy ctor\nauto h(int) { std::cout << "int" << std::endl;}\n// auto h(double) is not even delcared\n\nint main() {\n    f(1);\n    f(1.2);\n    g(1);\n    //g(1.2); // compile time error\n    h(1);\n    h(1.2); // round error\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

特殊成员函数的特殊之处在于声明/定义/ defaulting/ deleteing/根本不写一个函数如何影响另一个函数。

\n

本页对所有内容进行了解释,但需要仔细阅读。

\n

这是一个棘手的地方(我的粗体):

\n
\n

删除了隐式声明的移动构造函数

\n

如果满足以下任一条件,则类的隐式声明或默认移动构造函数被T定义已删除:

\n
    \n
  • T 具有无法移动的非静态数据成员(具有已删除、不可访问或不明确的移动构造函数);
  • \n
  • [\xe2\x80\xa6]
  • \n
\n

[\xe2\x80\xa6]

\n
\n

以上是什么意思?

\n

这是一个例子:

\n
// copyable but not movable\nstruct CNM {\n    CNM() {};\n    CNM(CNM const&) = default;\n    CNM(CNM&&) = delete;\n};\n\nstruct W {\n    W() {}\n    W(W&&) = default; // defaulted... but actually deleted!\n    CNM nm;\n};\n\nW w1;\nW w2{std::move(w1)}; // compile time error\n
Run Code Online (Sandbox Code Playgroud)\n

  • 前现代 C++ 相当于删除的是声明函数而不定义它。 (4认同)