根据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
。
答案 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 并指出,与此案有关的两条规则不适用
(7.2)const非类类型的非静态数据成员(或其数组),或者
[...]
(7.4)类类型M(或其数组)的直接非静态数据成员或由于重载分辨率([over.match])而无法复制/移动的直接基类M,用于查找M相应的赋值运算符,会导致歧义或功能从默认的赋值运算符中删除或无法访问。