For built-in types, such as int
, x++
yields the old value of x
. There is no storage associated with this, so it would be impossible for the expression to be an lvalue.
In C, ++x
yielded the new value of x
(and was not an lvalue). Since the object x
actually contains that same value, it is possible to have ++x
designate the object x
(i.e. be an lvalue). This is added functionality compared to yielding an rvalue, and the designer of C++ decided that this would be an improvement to the language.
For class types, it is possible overload any operator in such a way that use of the operator can yield an lvalue, xvalue, or prvalue. However it is considered good style to make overloaded operators have similar semantics to built-in operators, which is why it is normal for people to overload ++x
to yield an lvalue and to overload x++
to yield an rvalue.