Proposed resolution:
This wording is relative to N4993.
Modify [iterator.concept.contiguous] as indicated:
-1- The `contiguous_iterator` concept provides a guarantee that the denoted elements are stored contiguously in memory.
template<class I> concept contiguous_iterator = random_access_iterator<I> && derived_from<ITER_CONCEPT(I), contiguous_iterator_tag> && is_lvalue_reference_v<iter_reference_t<I>> && same_as<iter_value_t<I>, remove_cvref_t<iter_reference_t<I>>> && requires(const I& i) { { to_address(i) } -> same_as<add_pointer_t<iter_reference_t<I>>>; };-2- Let `a` and `b` be dereferenceable iterators and `c` be a non-dereferenceable iterator of type `I` such that `b` is reachable from `a` and `c` is reachable from `b`, and let `D` be iter_difference_t<I>. The type `I` models `contiguous_iterator` only if
(2.1) — `to_address(a) == addressof(*a)`,
(2.2) — `to_address(b) == to_address(a) + D(b - a)`,
(2.3) — `to_address(c) == to_address(a) + D(c - a)`,
(2.?) — `to_address(I{})` is well-defined,
(2.4) — `ranges::iter_move(a)` has the same type, value category, and effects as `std::move(*a)`, and
(2.5) — if `ranges::iter_swap(a, b)` is well-formed, it has effects equivalent to `ranges::swap(*a, *b)`.