用户提供的显式默认函数定义为已删除的情况

时间:2014-11-16 06:17:04

标签: c++

N3797::8.4.2/4 [dcl.fct.def.default]有以下引用:

  

如果函数是用户声明的而非显式的,则用户提供该函数   在第一次声明中违约或删除。用户提供的   明确默认的功能(即明确违约后的功能)   第一个声明)是在明确的地方定义的   违约; 如果将此类函数隐式定义为已删除,则为   程序格式不正确。

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

  

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

以下代码应抛出有关已删除函数调用的错误:

#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

2 个答案:

答案 0 :(得分:1)

以下示例对此进行了解释:

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

由于m_a是const成员,所以编译器会隐式删除副本分配运算符函数A& operator=(const A&)。所以你不能做以下事情

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的消息。但是,如果您绝对需要赋值运算符说要复制其他非const成员,则可以按如下所示明确定义它。

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(和可复制)成员。但是对于那些不了解这种行为的人,可能会误以为const成员(且不可复制)也被重新分配,从而导致各种错误。

答案 1 :(得分:0)

我的其他答案不正确。在您的情况下,A的copy-constructor不是用户提供的,因为它在第一次声明时被明确默认。用户提供的显式默认函数如下所示:

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是其数据成员。在声明构造不正确后明确默认构造函数。