Original answer
The rationale is given in N4284, which is the adopted version of the contiguous iterators proposal:
This paper introduces the term "contiguous iterator" as a refinement of random-access iterator, without introducing a corresponding contiguous_iterator_tag
, which was found to break code during the Issaquah discussions of Nevin Liber's paper N3884 "Contiguous Iterators: A Refinement of Random Access Iterators".
Some code was broken because it assumed that std::random_access_iterator
couldn't be refined, and had explicit checks against it. Basically it broke bad code that didn't rely on polymorphism to check for the categories of iterators, but it broke code nonetheless, so std::contiguous_iterator_tag
was removed from the proposal.
Also, there was an additional problem with std::reverse_iterator
-like classes: a reversed contiguous iterator can't be a contiguous iterator, but a regular random-access iterator. This problem could have been solved for std::reverse_iterator
, but more user-defined iterator wrappers that augment an iterator while copying its iterator category would have either lied or stopped working correctly (for example Boost iterator adaptors).
C++20 update
Since my original answer above, std::contiguous_iterator_tag
was brought back in the Ranges TS, then adopted in C++20. In order to avoid the issues mentioned above, the behaviour of std::iterator_traits<T>::iterator_category
was not changed. Instead, user specializations of std::iterator_traits
can now define an additional iterator_concept
member type alias which is allowed to alias std::contiguous_iterator_tag
or the previous iterator tags. The standard components has been updated accordingly in order to mark pointers and appropriate iterators a contiguous iterators.
The standard defines an exposition-only ITER_CONCEPT(Iter) which, given an iterator type Iter
, will alias std::iterator_traits<Iter>::iterator_concept
if it exists and std::iterator_traits<Iter>::iterator_category
otherwise. There is no equivalent standard user-facing type trait, but ITER_CONCEPT is used by the new iterator concepts. It is a strong hint that you should use these iterator concepts instead of old-style tag dispatch to implement new functions whose behaviour depends on the iterator category. That said concepts are usable as boolean traits, so you can simply check that an iterator is a contiguous iterator as follows:
static_assert(std::contiguous_iterator<Iter>);
std::contiguous_iterator
is thus the C++20 concept that you should use to detect that a given iterator is a random-access iterator (it also has a ranges counterpart: std::contiguous_range
). It is worth noting that std::contiguous_iterator
has a few additional constraints besides requiring that ITER_CONCEPT matches std::contiguous_iterator_tag
: most notably it requires std::to_address(it)
to be a valid expression returning a raw pointer type. std::to_address
is a small utility function meant to avoid a few pitfalls that can occur when trying to retrieve the address where a contiguous iterator points - you can read more about the issues it solves in Helpful pointers for ContiguousIterator
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…