There is much debate about unsigned. Without going too much into subjective territory, consider the following: What matters is not whether the value returned from rand() cannot be negative. What matters is that rand() returns a value of a certain type and that type determines what you can do with that value. rand() never returns a negative value, but does it make sense to apply operations on the value that make the value negative? Certainly yes. For example you might want to do:
auto x = rand() % 6 - 3;
If rand() would return an unsigned then this would lead to confusing bugs in code that looks ok.
Using unsigned for example for indices is a different story. An index is always positive. If you want to apply operations to it that turn the value negative then it is not an index anymore. rand() % 6 -3 on the other hand is a random number, be it positive or not.
A type is more than the range of values it can represent. Signed and unsigned integers have different semantics.
Note that C++20 introduced std::ssize. It’s the size of a container, it can only be positive. Nevertheless it is signed. That’s one example for positive values that are signed merely to allow signed arithmetics. Also it was not an option to change std::size to return a signed, because that would break existing code.
And as a sidenote consider that Java has no unsigned integer type at all, because unsigned arithmetics were considered too confusing.