This defines the iterator tuple based on the storage type of zippy,
instead of its type arguments. This way, we can support temporaries that
gets passed in and allow for them to be modified during iteration.
Because the iterator types to the tuple storage can have different types
when the storage is and isn't const, this defines a const iterator type
and non-const begin/end functions. This way we avoid unintentional
casts, e.g., trying to cast vector<bool>::reference to
vector<bool>::const_reference, which may be unrelated types that are
not convertible.
This patch is a general and free-standing improvement but my primary use
is in the implemention a version of enumerate that accepts multiple ranges:
D144583.
These could be static_asserts instead, perhaps? (similarly below)