Question

In GCC 4.6, it is possible to inherit a parent's assignment operators even when the child's assignment operators are implicitly deleted due to a move constructor. In later versions of GCC (as well as Clang), this is no longer possible. What is the proper way to have the child class use the parent's assignment operators?

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

struct B : public A
{
  B() {}
  B(B && other) {}

  using A::operator=;
};

int main()
{
  B b1, b2;
  b1 = b2; // error: use of deleted function because B's operator= is implicitly deleted due to move constructor
  return 0;
}
Was it helpful?

Solution

A function that is deleted is still declared, only the definition is deleted. Expanding that in your class definition:

struct B : A {
   using A::operator=;               // A& operator=(const A&)
   B& operator=(const B&) = delete;
};

At this point, you can note that there are two declarations for operator= in the derived type, the first one (brought into scope by means of a using-declaration) takes a const A& argument, while the second one takes a const B& and is deleted.

When you later try the assignment:

B b1, b2;
b1 = b2;

Both declarations are seen by the compiler and the second one is a better match. Because it is marked as deleted you get the error. If you had, on the other hand assigned a A object it would have worked as expected:

B b1, b2;
b1 = static_cast<A&>(b2); // works, BUT...

The problem with this approach is that it is only copying the base subobjects which is probably not what you want. If you just want the same behavior you would have had if the assignment had been generated by the compiler you need to ask for it:

struct B : A {
   // ...
   B& operator=(const B&) = default;
};

OTHER TIPS

It would depend on what you want to have happen when you assign a derived type to itself. If you want the child assignment operator to work like "normal" despite the move operator suppressing the implicit generation, you can simply bring the child assignment back into the class, using this:

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

This would likely be equivalent to what GCC 4.6 did. I believe GCC 4.6 doesn't properly suppress generated operators as the standard requires, so you were probably just getting the normal assignment operator behavior, along with any overloads from the base class that your using declaration was pulling in.

If you actually only want to assign the base part of the class, you would need to implement your own assignment operator:

    B &operator=( B const &that ) {
        static_cast<A&>(*this) = that;
        return *this;
    }

Unfortunately I don't have GCC 4.7 to try out right now, but I wouldn't be surprised if you are actually getting the base class assignment operator in your derived class, but the derived class's deleted assignment operator is a better match for your example. You could test this out by trying this line in your main():

    b1 = static_cast<A const&>(b2);

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top