Here's evidence that it is:
inline
constexpr std::size_t prev(std::size_t i) {
--i;
return i;
}
int main() {
static const std::size_t i = 0;
static_assert(prev(i) == std::size_t(-1), "Decrementing should give std::size_t(-1)");
return 0;
}
That compiles happily with -std=c++14
.
I came upon this because I had a loop indexing over a std::vector
and wanted to loop backward, so I changed it to
for (std::size_t i = std::min(idx, v.size() - 1); i != std::size_t(-1); --i) { ... }
Now, I realize I could use std::vector::reverse_iterator
, but my real question now is, is the behavior I'm expecting well-defined?
Yes, this behavior is guaranteed.
std::size_t
is an unsigned integer type. Arithmetic on unsigned integers always has well defined semantics:
Unsigned integer arithmetic is always performed modulo 2n where n is the number of bits in that particular integer.
Specifically considering the built-in pre-decrement and post-decrement operators:
[T]he expression
--x
is exactly equivalent tox -= 1
. ...
[T]he expressionx--
modifies the value of its operand as if by evaluatingx -= 1
So the decrement operator does perform an arithmetic operation.