Let's say I have the following minimal example class:
#include <iostream>
class Foo {
public:
Foo() = default;
Foo(const Foo&) = default;
Foo(Foo&&) noexcept = default;
Foo& operator=(const Foo& rhs) {
std::cout << "copy\n";
return *this;
}
Foo& operator=(Foo&& rhs) noexcept {
std::cout << "move\n";
return *this;
}
Foo operator+(const Foo& rhs) const {
Foo x; // with some calculation
return x;
}
};
int main() {
Foo a, b, c;
a = b + c;
}
This prints move
as expected. Now according to Effective C++ Item 3, I should return const Foo
from operator+
to avoid construct like a + b = c
, ie:
// To avoid a + b = c
const Foo operator+(const Foo& rhs) const {}
Unfortunately, this suddenly starts calling copy assignment instead of move assignment operator. [I'm using gcc 4.8.4 on Ubuntu, but it is probably nothing related to compiler]
How can I ensure that a + b = c
fails to compile and in the same time move assignment is called for a = b + c
? Or with the introduction of move semantics, is there no way to achieve both of them in the same time?
I have ended up using lvalue reference qualifier as pointed by Caninonos in comment and by max66 in now deleted answer (but 10k users can see it).
Foo& operator=(const Foo& rhs) & {}
Foo& operator=(Foo&& rhs) & noexcept {}
It is simple to implement and it provides a better interface design since assignment to anything other that lvalue doesn't sound meaningful and a possible source of bug.
However, it should be noted that the possibility of writing a + b = c
by mistake is very low. Also compiler generated assignment operators are not lvalue reference qualified and we can write a + b = c
with standard types, eg with std::string
or with std::complex
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.