stumbled upon another type of multi-dimensional iterator that you just can't have in STL in it's current form :
github.com/ClaasBontus/miterat

Goal: Iterate over multiple containers in tandem.
Solution: Iterator tuple wrapper that applies all relevant operations to it's elements.
Problem: the range based for loop, the algorithms library, and the whole concept of iterators relies on equality comparison. The loops increment the first(begin) iterator while it's not equal to last(end) iterator, some algorithms exit early if first == last, etc. In this case we want the iteration to stop when one of the ranges is exhausted, therefore the inequality of the tuple must be implemented as a conjunction of element-wise inequality comparisons, that is the tuples will be unequal only if all their corresponding elements are all individually unequal. The tragedy is that this makes absolutely no sense in any other context and is a bonkers way to implement inequality for a tuple (or any other vector/collection type), since any two tuples that have only one element in common will be considered equal. Alas this is what you have to do to satisfy the standard library. The only solution to this would be to change the iterator concept to use a different function (maybe called std::reaches(first, last)), that will just default to equality comparison unless specialized for a given type. The use of equality comparison is already conceptually dubious for ranges that use sentinel end iterators (like input streams, lazy generators, or when you want to do less than because some overflow is allowed and expected), but when you try to up the dimensions even in the trivial cases it just completely breaks apart.

Follow

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 in OP -_-

Sign in to participate in the conversation
Qoto Mastodon

QOTO: Question Others to Teach Ourselves. A STEM-oriented instance.

An inclusive free speech instance.
All cultures and opinions welcome.
Explicit hate speech and harassment strictly forbidden.
We federate with all servers: we don't block any servers.