Take a look at this article about value categories.
Value categories
Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category. [...]
prvalue
The following expressions are prvalue expressions:
[...]
- function call or an overloaded operator expression of non-reference return type, such as str.substr(1, 2)
OK, so we know that expressions func1()
and func2()
are prvalues.
[...]
rvalue
An rvalue expression is either prvalue or xvalue.
Now we know that prvalues are rvalues.
Properties:
[...]
An rvalue can't be used as the left-hand operand of the built-in assignment or compound assignment operators.
[...]
Here is the important part. Note that the rule only excludes built-in assignment. Copy assignment operator of a class type is still allowed.
So, the difference between built-in operators, and operators of class types is that they are treated differently by the rules of the language.
Now, you might be wondering, why is assignment not allowed for built-in types? Well, there is no use case for it. The assignment has no side-effects (besides changing the value of the left hand operand) and the return value is discarded. If you write it, you've most likely made a mistake. Disallowing it is helpful to the programmer.
Now, you might be wondering, isn't assigning to an rvalue class type also useless? Well, it might not be! Class types can have user defined assignment operators that have side-effects. And class types can have destructors that have side-effects depending on the previously performed assignment. I cannot guarantee that this was the reasoning that Bjarne or the committee used when they specified the language, but those are my thoughts on the matter.