Repeating the error message:
main.cpp(56): error C2280: 'Rect &Rect::operator =(const Rect &)': attempting to reference a deleted function
This is fairly clear: the member function operator=
with parameter const Rect &
has been delete
d, but your code tries to call it on the line test = Rect();
.
You then say:
The compiler tries to tell me that, the copy constructor of class Rect is a deleted function
However, you misread the error. The error is about the function operator =
, which is called copy assignment operator. This is a different function to copy constructor, which would look like Rect::Rect(const Rect &)
.
You say that you tried adding:
Rect& operator=(const Rect&) = default;
However this would make no difference. The compiler-generated operator=
function is delete
d because it is not possible for the compiler to generate one (explanation for this comes below); writing = default;
does not change this. You have to actually write your own body for operator=
which performs the actions that you want to occur when an assignment happens.
In Standard C++ it is not permitted to have an anonymous struct, let alone an anonymous struct inside an anonymous union. So you are really out on your own here. The rules your compiler is using regarding operator=
, copy constructor, etc. are not covered by any Standard.
A version of your Rect
that is compilable in Standard C might look like:
class Rect
{
public:
struct S1 {
Vector p1, p2;
S1(Vector p1, Vector p2): p1(p1), p2(p2) {}
};
struct S2 {
float p1x, p1y, p2x, p2y;
};
union {
struct S1 s1;
struct S2 s2;
};
Rect() : s1({0, 0}, {0, 0}) {}
Rect(Vector p1, Vector p2) : s1(p1, p2) {}
};
So far, so good. For this class, the implicitly-declared operator=
is defined as deleted. To see why , we first have to look at the implicitly-declared special functions for the anonymous union, because the behaviour of implicitly-declared function for a class depends on the behaviour of the same operation for each of its members.
The relevant rule here for the union is C++14 [class.union]/1:
If any non-static data member of a union has a non-trivial default constructor , copy constructor, move constructor, copy assignment operator, move assignment operator, or destructor, the corresponding member function of the union must be user-provided or it will be implicitly delete
d for the union.
Vector
has a non-trivial operator=
, because you write your own body for it. Therefore S1
has non-trivial operator=
, because it has a member with non-trivial operator=
, and so according to the above quote, the implicitly-declared operator=
for the union is delete
d.
Note that there is no error about the copy-constructor: Vector
does have a trivial copy-constructor, so the union does too.
To fix this error you could do one of two things:
- Change
Vector::operator=
to be trivial, either by removing your definition entirely, or making it = default;
- Write
operator=
for the Rect
class
Now, how would you write your own operator=
? Do you do s1 = other.s1;
, or do you do s2 = other.s2;
? The compiler can't know that on its own, which is the reason behind the implicitly-declared operator=
being deleted.
Now, it seems you overlooked (either accidentally or deliberately) the rule about active members in C++:
In a union, at most one of the non-static data members can be active at any time
This means that if s1
is the last member set, then you'd have to do s1 = other.s1;
. Or if s2
is the last member set, you'd have to do s2 = other.s2;
.
The copy-constructor doesn't run into this problem because it is trivial: the compiler can generate a bit-wise copy and that will correctly implement the copy regardless of which member was active. But since your operator=
is non-trivial, that would not be possible.
For example, imagine if you actually had a union of std::string
and std::vector
- bitwise copy doesn't work for either of those and you need to know which one is active in order to perform the copy.
Reiterating: In standard C++ it is not permitted to read a member of a union other than the one most recently written to. You can't use unions for aliasing. C++ has other language tools to achieve what you might do in C with union aliasing, see here for more discussion.
Based on the choice of members for your anonymous structs I suspect that this is what you intended to do. If you really want to go ahead with this approach, relying on your compiler implementing union aliasing as a non-standard extension, then my advice would be to use the defaulted operator=
for your Vector
class.