The reason is historical. In the initial days of the language, there was simply no way for user code to express that a type's copy-assignment operator should only work on l-values. This was only true for user-defined types of course; for in-built types assignment to an r-value has always been prohibited.
int{} = 42; // error
Consequently, for all types in the standard library, copy-assignment just "works" on r-values. I don't believe this ever does anything useful, so it's almost certainly a bug if you write this, but it does compile.
std::string{} = "hello"s; // ok, oops
The same is true for the iterator type returned from v.begin()
.
From C++11, the ability to express this was added in the language. So now one can write a more sensible type like this:
struct S
{
S& operator=(S const &) && = delete;
// ... etc
};
and now assignment to r-values is prohibited.
S{} = S{}; // error, as it should be
One could argue that all standard library types should be updated to do the sensible thing. This might require a fair amount of rewording, as well as break existing code, so this might not be changed.
v.begin().operator=(v.begin().operator++())
. It is sometimes useful, but it does lead to odd code compiling when those member functions are overloaded operators. – Earthmanfoo
should take the iterator by value. That’s how iterators are intended to be used. It’s very unusual to traffic in references to iterators. – Sicyonfoo()
it is there just to show thatbegin()
returns rvalue. – Phenetidine