45
struct A
{
    A();

    A(const A&);
    A& operator =(const A&);

    A(A&&) = delete;
    A& operator =(A&&) = delete;
};

struct B
{
    B();

    B(const B&);
    B& operator =(const B&);    
};

int main()
{
    A a;
    a = A(); // error C2280

    B b;
    b = B(); // OK
}

我的编译器是 VC++ 2013 RC。

错误 C2280:“A &A::operator =(A &&)”:试图引用已删除的函数

我只是想知道为什么编译器在删除A& operator =(const A&);时不尝试?A& operator =(A&&)

这种行为是由 C++ 标准定义的吗?

4

2 回答 2

71
a = A(); // error C2280

右边的表达式是临时的,这意味着它将查找operator=(A&&)并看到它被删除。因此错误。没有进一步的搜索。

=delete并不意味着“不要使用我,而是使用下一个最好的”。它的意思是,“当你需要我的时候不要使用我——而是在野外独自一人。”

这是另一个例子。如果我希望我的类的实例X仅使用long而不使用其他类型创建(即使它转换为 long!),那么我将声明class X为:

struct X
{
     X(long arg); //ONLY long - NO int, short, char, double, etc!

     template<typename T>
     X(T) = delete;
};

X a(1);  //error - 1 is int 
X b(1L); //ok    - 1L is long

这意味着,重载决议是编译器看到该=delete部分之前执行的——因此会导致错误,因为发现选定的重载已被删除。

希望有帮助。

于 2013-10-09T07:48:20.063 回答
23

当你=delete是一个函数时,你实际上是在删除它的定义

8.4.3 删除的定义 [dcl.fct.def.delete]

1形式的函数定义:

属性说明符 seqopt decl 说明符 seqopt 声明符 = 删除;

称为已删除定义。具有已删除定义的函数也称为已删除函数

但是这样做,您也声明了该功能。引用标准[1]

4已删除的函数是隐式内联的。[ 注意:单一定义规则 (3.2) 适用于已删除的定义。—尾注]删除的函数定义应是函数的第一个声明[...]

因此,通过这样做a = A(),编译器实际上解析为,A::operator=(A&&)因为它已被声明(不是A::operator(const A&),因为它对A&&r 值“更具约束力”)。但是,随着其定义被删除,该行格式错误。

2隐式或显式引用已删除函数的程序,而不是声明它,是格式错误的。


[1]这里强调句的语气实际上是祈使句。该标准指示声明函数=deleted 必须首先出现在它的其他声明之前。但是,它仍然支持删除函数也声明该函数的事实。

于 2013-10-09T08:00:11.543 回答