Deleted implicitly-declared copy assignment operator
Asked Answered
C

2

7

According to the C++ reference on Copy assignment operator:

A defaulted copy assignment operator for class T is defined as deleted if any of the following is true

T has a non-static data member of non-class type (or array thereof) that is const ...

I was hoping to create a case where I had a const class-type data member and a defaulted copy assignment operator not defined as deleted. In doing so, I found a discrepancy between clang and gcc. Consider the following code:

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
}

When I compile this with g++ -std=c++14 I get the following errors:

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

This does, comma, however, compile with clang, as the reference seems to indicate that it should. Am I in error? Which compiler is correct?

I'm using gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04) and clang version 6.0.0-1ubuntu2.

Circumbendibus answered 8/11, 2018 at 18:6 Comment(1)
In general you want to use C++ since that gives the question a much wider audience than C++ version specific tags.Jereme
S
4

It seems that clang is right,

Although not yet confirmed, there is a report on the subject for gcc and as it was pointed out, the two rules relevant to this case don't apply

[class.copy.assign]/7

(7.2) a non-static data member of const non-class type (or array thereof), or

[...]

(7.4) a direct non-static data member of class type M (or array thereof) or a direct base class M that cannot be copied/moved because overload resolution ([over.match]), as applied to find M's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator.

Siloa answered 8/11, 2018 at 18:55 Comment(0)
J
3

It sure looks like clang is correct, section [class.copy.assign]p7 says:

A defaulted copy/move assignment operator for class X is defined as deleted if X has:

  • (7.1) a variant member with a non-trivial corresponding assignment operator and X is a union-like class, or
  • (7.2) a non-static data member of const non-class type (or array thereof), or
  • (7.3) a non-static data member of reference type, or
  • (7.4) a direct non-static data member of class type M (or array thereof) or a direct base class M that cannot be copied/moved because overload resolution ([over.match]), as applied to find M's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator.

A defaulted move assignment operator that is defined as deleted is ignored by overload resolution ([over.match], [over.over]).

and none of those cases hold.

Although I have to say a const copy assignment operator that returns void feels novel, the wording in [class.copy.assign]p1 sure seems to allow.

There is an open gcc bug report for a similar case Const subobject with const assignment operator, but operator anyway deleted with code as follows:

class bar
{
public:
    bar() {}

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

class foo
{
    bar const v;
};

int main()
{
    foo a;

    a = foo();
}

The reporter points out the same section as I do.

Jereme answered 8/11, 2018 at 18:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.