istream objects all have their copy constructors and assignment operators hidden, meaning that you can't ever create copies of them, and therefore can't pass or return by-value.
If you define your own class and don't hide its assignment operator/copy constructor then you can make copies wherever you like.
Something to consider when writing your operators is "Does the operator
semantically modify its current object?" Anything involving assignment obviously would be expected to modify the current object, therefore returning a copy would just be weird and probably wrong.
Having an operator return by-value or by-reference really should depend on the operator - it should reflect the way that the operator is expected to work, because if you do it differently, then your operator may behave in an unusual fashion relative to its behaviour for other types such as int or std::string.
So, the following operators are expected to return by-value because they shouldn't change their current object (typically you'd make these into const members)
Whereas these operators would all be expected to modify their current object, therefore they should return by-reference
- Not an exhaustive list, just to give you the general idea.