Can anybody explain why this code compiles:
typedef struct longlong
{
unsigned long low;
long high;
}
longlong;
typedef longlong Foo;
struct FooStr
Using operators on objects of class type means to call a function (either a member function of the left-hand operand, or a free function taking the left-hand operand as first argument). This is known as operator overloading.
It's fine to call functions on rvalues so there is no compilation error.
When implementing the overloaded assignment operator, you can mark it so that it can not be called on an rvalue, but the designer of whatever class you are using chose not to do that.
f.GetBar() = m2; // Here I'd expect an error such as // "error: lvalue required as left operand of assignment"
Your expectation is in error. This rule only applies to objects of built-in type.
[C++14: 3.10/5]:
An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [ Example: a member function called for an object (9.3) can modify the object. —end example ]
Recall that your =
here is actually a call to operator=
, which is a function.
Reasons for this behavior were described in other answers.
One way to avoid this behavior would be qualifying your return type with const
:
struct FooStruct
{
...
const Foo GetBar() {return bar;}
};
You cannot assign values to const
objects, so the compiler will complain.
This works because longlong
is a class, and as such =
is longlong::operator =
, the implicitly-defined assignment operator. And you can call member functions on temporaries as long as they're not qualified with &
(the default operator =
is unqualified).
To restrict the assignment operator to lvalues, you can explicitly default it with an additional ref-qualifier:
struct longlong
{
longlong &operator = (longlong const &) & = default;
// ^
// ...
};