Is v.begin() lvalue or rvalue?
It's an rvalue.
auto& it = v.begin();
This is ill-formed because an lvalue reference to non-const cannot be bound to an rvalue.
v.begin() += 1;
This advances the temporary iterator to the beginning, and discards the result.
It "works" if the goal is to do nothing useful.
cout << *(v.begin()); // output is 1
This indirects through the iterator to beginning.
cout << *(v.begin()+1); // output is 2
This advances the iterator to the beginning, and instead of discarding the result, it indirects through the resulting iterator.
v.begin() cannot be changed? then why v.begin()+=1 code is not error?
You can change a temporary object returned by the function. But changes to that temporary object have no effect on what v.begin()
will return in future.
Yes, v.begin() += 1
is a compound assignment to an rvalue. If you come from C, you may be surprised by this since you may have learned that "only lvalues may be the left hand operand of an assignment". But in C++ that only applies to fundamental types, and it does not apply to class types in general.
When defining assignment operator overloads for your own classes, it may be useful to use lvalue ref qualified member functions which would prevent direct assignment to an rvalue, and thus would prevent code such as v.begin() += 1
.
Ref qualifiers were added to the standard later (in C++11), so the pre-existing standard library classes couldn't have those qualifiers, and so assigning rvalues of standard types is unfortunately possible. There was a proposal to add the qualifiers, but it didn't pass due to concerns of backward compatibility. I don't know why, but specifications of new standard classes haven't had qualified assignment operators either.