The most popular operator which should return reference is operator=
class Alpha
{
int x;
int y;
std::string z;
public:
void print()
{ cout << "x " << x << " y " << y << " " << z << '\n'; }
Alpha(int xx=0, int yy=0, std::string zz=""): x(xx), y(yy), z(zz) {}
Alpha operator=(Alpha& another)
{
x = another.x;
y = another.y;
z = another.z;
return *this;
}
};
int main()
{
Alpha a(3,4,"abc"),b,c;
b=c=a;
return 0;
}
Clang says this:
clang++-3.6 new.cxx -o new new.cxx:70:3: error: no viable overloaded '=' b=c=a; ~^~~~ new.cxx:34:8: note: candidate function not viable: expects an l-value for 1st argument Alpha operator=(Alpha& another) ^ 1 error generated.
gcc this:
new.cxx:34:8: note: no known conversion for argument 1 from ‘Alpha’ to ‘Alpha&’
But I can't understand what's the problem in theory. What I think happens:
c
. It receives object a
by reference, copies it's values to c and returns anonymous copy of it's self (of object c
): Copy soncstructor is called.b
. It requires rvalue ref, but we have only written lvalue reference, so the error occurs.I have added rval operator= and copy constructor, which receives lvalue reference and everything works, now I have no idea why (I should have written rvalue copy constructor which receive const Alpha& s
or Alpha&& s
):
class Alpha
{
int x;
int y;
std::string z;
public:
void print()
{ cout << "x " << x << " y " << y << " " << z << '\n'; }
Alpha(int xx=0, int yy=0, std::string zz=""): x(xx), y(yy), z(zz) {}
//Alpha(Alpha&& s): x(s.x), y(s.y), z(s.z) {}
Alpha(Alpha&& ) = delete;
Alpha(Alpha& s): x(s.x), y(s.y), z(s.z) {}
Alpha operator=(Alpha& another)
{
x = another.x;
y = another.y;
z = another.z;
return *this;
}
Alpha operator=(Alpha&& another)
{
x = another.x;
y = another.y;
z = another.z;
return *this;
}
};
This signature for an assignment operator
Alpha operator=(Alpha& another)
is unusual in two ways. The first is that it returns a copy of the assigned-to object. Very rare to do that. The other is that it accepts a non-const reference as a parameter.
The non-const reference makes it not accept temporary objects as a parameter (as those will only bind to a const lvalue reference).
In combination this means that the temporary returned from the first operator=
can not be used as a parameter to the second operator=
.
Your options are to either return a reference, or to make the parameter Alpha const&
. Both options would work individually, or in combination.
The third option, as you found out, is to explicitly add a move assignment operator, using Alpha&&
that specifically accepts temporaries.
The standard way though is to declare the copy assignment operator
Alpha& operator=(Alpha const& other);
unless you have very specific reasons for selecting another signature.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With