C++ 11中删除函数的确切语义是什么?

xml*_*lmx 45 c++ overloading language-lawyer c++11 semantics

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
}
Run Code Online (Sandbox Code Playgroud)

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

错误C2280:'A&A :: operator =(A &&)':尝试引用已删除的函数

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

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

Naw*_*waz 70

a = A(); // error C2280
Run Code Online (Sandbox Code Playgroud)

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

=delete不会意味着"不要用我,而是使用下一个最好的之一".这意味着," 当你需要我的时候不要用 - 而是在野外独处."

这是另一个例子.如果我想我的类的实例X,以仅创建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
Run Code Online (Sandbox Code Playgroud)

这意味着,重载分辨率在编译器看到该部件之前执行=delete - 因此导致错误,因为发现所选的重载被删除.

希望有所帮助.


Mar*_*cia 23

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

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

1表单的函数定义:

attribute-specifier-seqopt decl-specifier-seqopt declarator = delete;

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

但通过这样做,你也宣布了这个功能.引用标准[1]:

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

所以做a = A()时,编译器实际上解析到A::operator=(A&&),因为它已申报(不A::operator(const A&),因为A&&"更结合",以r值).但是,如果删除其定义,则该行格式不正确.

2除了声明它之外,隐式或显式引用已删除函数的程序是不正确的.


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

  • +1此外,要完成OP似乎想要的内容,他所要做的就是声明用户定义的copy-constructor/copy-asignment-operator成员.通过**C++§12.8[class.copy]**,所述成员(复制)的用户定义版本的存在压缩了移动的*default*实现(分别).也就是说,如果你声明两者,你只能移动*和*复制.如果OP想要逃避移动,只需声明复制**. (2认同)
  • @WhozCraig虽然我不知道为什么OP不想使用移动语义.(我对此感到内疚,事实上,我提出了一个问题,我并不为此感到骄傲......) (2认同)