【问题标题】:A case when a user-provided explicitly-defaulted function defined as deleted用户提供的显式默认函数定义为已删除的情况
【发布时间】:2014-11-16 06:17:03
【问题描述】:

下面是N3797::8.4.2/4 [dcl.fct.def.default]的引用:

一个函数是用户提供的,如果它是用户声明的而不是明确的 在第一次声明时违约或删除。用户提供的 显式默认函数(即,在其后显式默认) 第一个声明)在显式定义的地方定义 违约; 如果这样的函数被隐式定义为删除,则 程序格式错误。

我试图发明一个反映该规则的示例。因为,标准说:

如果类定义没有显式声明一个副本 构造函数,一个是隐式声明的。如果类定义 声明一个移动构造函数或移动赋值运算符,the 隐式声明的复制构造函数被定义为删除;

下面的代码应该抛出一个关于删除函数调用的错误:

#include <iostream>

using namespace std;

struct A
{ 
    A(){ }
    A(const A&&){ cout << "A(const&&)" << endl; }
    A(const A&) = default;
};

A a;

A b = a;

int main() {
}

但它工作正常。你能提供一个反映这一点的实际例子吗?

DEMO

【问题讨论】:

  • 我认为你混淆了 implicituser-provided 这两个术语,如果你声明一个函数,根据定义它不是 implicit 。一个特殊的函数可以在它的第一个声明中选择defaulted,在这种情况下它不是user-provided,但这不会使它成为implicit。跨度>

标签: c++


【解决方案1】:

下面的例子解释它:

class A {
public:
    A(int a) : m_a(a) {} 
    const int m_a;
};

由于 m_a 是一个 const 成员,编译器会隐式删除复制赋值运算符函数A&amp; operator=(const A&amp;)。所以你不能做以下事情

int main() {
    A var1(1);
    A var2(3);
    var2 = var1;
}

您应该会收到类似copy assignment operator implicitly deleted 的编译时错误。现在你会很想显式默认它

class A {
public:
    A(int a) : m_a(a) {} 
    A& operator=(const A& other) = default;

    const int m_a;
};

您仍然会收到编译时错误,并且可能会看到类似explicitly defaulted function was implicitly deleted 的消息。但是,如果您绝对需要赋值运算符来复制其他非常量成员,您可以如下显式定义它。

class A {
public:
    A(int a) : m_a(a) {} 
    A& operator=(const A& other) {
    m_b = other.m_b;
    }

const int m_a;
int m_b = 0;
};

我认为这背后的原因是显而易见的。在构造过程中初始化它们之后,我们不能重新分配 const 变量(和不可复制的成员)。尽管有人可能会争辩说应该允许只复制非常量(和可复制)成员的默认行为。但是对于不了解这种行为的人来说,可能会产生错误的印象,即 const 成员(和不可复制的)也被重新分配,从而导致各种错误。

【讨论】:

    【解决方案2】:

    我的另一个答案不正确。在您的情况下,A 的复制构造函数不是用户提供的,因为它在其第一个声明中被明确默认。用户提供的显式默认函数如下所示:

    struct X
    {
        X();
    };
    
    X::X() = default;
    

    该子句与构造函数在默认位置处被隐式删除的时间有关。举个例子:

    struct X
    {
        X(X&&); // user-declared move-constructor, deletes X's copy-constructor
    };
    
    struct Y
    {
        X x; // data member with deleted copy-constructor deletes Y's
             // copy-constructor
        Y(Y const&);
    };
    
    // program is ill-formed. Y's copy-constructor was implicitly deleted
    Y::Y(Y const&) = default;
    

    由于X 有一个隐式删除的复制构造函数,因此Y 有一个隐式删除的复制构造函数,因为x 是它的数据成员。在声明格式错误后显式默认构造函数。

    【讨论】:

    • 这有点愚蠢和不一致。删除继承并执行 Derived(Derived&amp;&amp;) { } 不会导致此类错误。让我觉得很奇怪。
    • @Rapptz 我确信有一个与这种情况有关的引用(用户提供的 move-ctor 不会删除同一类中显式默认的 copy-ctor)。我认为这个例子适用于 OP 的报价。
    • 确实,谢谢。 12.8/11 涵盖了所有这些情况。
    猜你喜欢
    • 2015-01-08
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-24
    相关资源
    最近更新 更多