删除隐式声明的副本分配运算符

时间:2018-11-08 18:06:05

标签: c++ g++ c++14 clang++ assignment-operator

根据Copy assignment operator上的C ++参考:

  

如果满足以下任一条件,则将默认的类别T的默认副本分配运算符定义为已删除

     

T具有非类类型(或其数组)的非静态数据成员,该成员为const ...

我希望创建一个实例,其中我有一个const类类型数据成员和一个未定义为删除的默认副本分配运算符。这样,我发现clang和gcc之间存在差异。考虑以下代码:

struct B {
  void operator=(const B&) const {}
};

struct A {
  const B b{};
  A& operator=(const A&) = default;
};

int main() {
  A a1{}, a2{};
  a1 = a2;       //only works with clang
  B b1{}, b2{};
  b1 = b2;       //works in both
}

当我使用g++ -std=c++14进行编译时,出现以下错误:

In member function ‘A& A::operator=(const A&)’:
error: non-static const member ‘const B A::b’, can’t use default assignment operator
note: synthesized method ‘A& A::operator=(const A&)’ first required here

但是,确实会用clang进行编译,因为参考文献似乎表明它应该这样做。我有错吗?哪个编译器是正确的?

我正在使用gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)clang version 6.0.0-1ubuntu2

2 个答案:

答案 0 :(得分:1)

[class.copy.assign]p7节说:“ c语似乎正确”。

  

默认将类X的复制/移动赋值运算符定义为   如果X具有以下条件,则将其删除:

     
      
  • (7.1)具有非平凡的对应赋值运算符且X是类联合类的变体成员,或
  •   
  • (7.2)const非类类型的非静态数据成员(或其数组),或
  •   
  • (7.3)引用类型的非静态数据成员,或
  •   
  • (7.4)无法复制/移动的类类型M(或其数组)的直接非静态数据成员或直接基类M   重载分辨率([over.match]),用于查找M   相应的赋值运算符,导致歧义或   从默认分配中删除或无法访问的功能   运算符。
  •   
     

定义为已删除的默认移动分配运算符为   被重载分辨率([over.match],[over.over])忽略。

所有这些案件都不成立。

尽管我不得不说一个返回空值的 const 复制赋值运算符听起来很新颖,但是[class.copy.assign]p1中的措辞肯定是允许的。

对于类似案例Const subobject with const assignment operator, but operator anyway deleted,有一个开放的gcc错误报告,其代码如下:

class bar
{
public:
    bar() {}

    bar const & operator=(bar const &) const
    {
        return *this;
    }
};

class foo
{
    bar const v;
};

int main()
{
    foo a;

    a = foo();
}

记者指出与我相同的部分。

答案 1 :(得分:1)

似乎c是正确的,

尽管尚未确认,但gcc的主题上有report 并指出,与此案有关的两条规则不适用

[class.copy.assign]/7

  

(7.2)const非类类型的非静态数据成员(或其数组),或者

     

[...]

     

(7.4)类类型M(或其数组)的直接非静态数据成员或由于重载分辨率([over.match])而无法复制/移动的直接基类M,用于查找M相应的赋值运算符,会导致歧义或功能从默认的赋值运算符中删除或无法访问。