Alternatively you can avoid changing the iterator concept by changing the algorithms, leaning onto the elementwise logical negation operator ~.
For this to make sense you have to introduce a new type: an array of bools with an associated reduction operation - conjunction or disjunction, that would represent the equality comparison in each dimension and contextually convert to a boolean, by performing the reduction. The == operator will return such an array with conjunciton, since that's what makes more sense for the tuple in general. Now the logical ! in order to also remain sensible will need to negate the elements of the array AND change the conjunction to a disjunciton, adhering to De Morgan's law. The elementwise ~ however has no such obligations of logical consistency (it's wavy, it's chaotic, it's insaneee) and can happily just negate the elements leaving the reduction operation untouched. This coincidentally is both exactly what we need for loop conditions and exactly what we always had when working with integer types as bit vectors (so hopefully it shouldn't be that alien of a syntax). What I'm getting at is that the range based for loop and algorithms should use ~(first == last) instead of (first != last) as a loop condition. Unfortunately the (fisrt == last) for early returns and such, will turn into ~(first != last) with this approach... that's double negation... disgusting... and I forgot the #cpp in OP -_-