So this is really just something I can't make sense of semantically. Assignment chaining make sense for copy semantics:
int a, b, c{100};
a = b = c;
a, b, and c all are 100.
Try a similar thing with move semantics? Just doesn't work or make sense:
std::unique_ptr<int> a, b, c;
c = std::make_unique<int>(100);
a = b = std::move(c);
This doesn't even compile, because a = b is a copy assignment, which is deleted. I could make an argument that after the final expression executes, *a == 100 and b == nullptr and c == nullptr. But this isn't guaranteed by the standard. This doesn't change much:
a = std::move(b) = std::move(c);
This still involves copy assignment.
a = std::move(b = std::move(c));
This one actually does work, but syntactically it is a huge deviation from copy assignment chaining.
Declaring an overloaded move assignment operator involves returning an lvalue reference:
class MyMovable
{
public:
MyMovable& operator=(MyMovable&&) { return *this; }
};
But why isn't it an rvalue reference?
class MyMovable
{
public:
MyMovable() = default;
MyMovable(int value) { value_ = value; }
MyMovable(MyMovable const&) = delete;
MyMovable& operator=(MyMovable const&) = delete;
MyMovable&& operator=(MyMovable&& other) {
value_ = other.value_;
other.value_ = 0;
return std::move(*this);
}
int operator*() const { return value_; }
int value_{};
};
int main()
{
MyMovable a, b, c{100};
a = b = std::move(c);
std::cout << "a=" << *a << " b=" << *b << " c=" << *c << '\n';
}
Interestingly this example actually works as I expect, and gives me this output:
a=100 b=0 c=0
I'm not sure if it shouldn't work, or why it does, especially since formally move assignment isn't defined this way. Quite frankly this just adds more confusion in an already-confusing world of semantic behaviors for class types.
So I've brought up a few things here, so I'll try to condense it into a set of questions:
- Are both forms of assignment operators valid?
- When would you use one or the other?
- Is move assignment chaining a thing? If so, when/why would you ever use it?
- How do you even chain move assignment that returns lvalue references in a meaningful way?