I remember having read that the motivation for [forward.iterators]/6 (requiring that, given two iterators a
and b
, a == b
if and only if *a
and *b
are bound to the same object) was to support reverse_iterator
s. Am I remembering correctly?
cppreference.com notes that
For a reverse iterator
r
constructed from an iteratori
, the relationship&*r == &*(i-1)
is alwaystrue
(as long asr
is dereferenceable); thus a reverse iterator constructed from a one-past-the-end iterator dereferences to the last element in a sequence.
and also:
std::reverse_iterator
does not work with iterators whose dereference returns a reference to a member of*this
(so-called "stashing iterators"). An example of a stashing iterator isstd::filesystem::path::iterator
.
However, it is also stated that:
std::reverse_iterator
is an iterator adaptor that reverses the direction of a given iterator, which must be at least aLegacyBidirectionalIterator
or modelbidirectional_iterator
(since C++20).
which is exactly what the standard says.
If I’m not mistaken, C++20 bidirectional_iterator
s no longer require [forward.iterators]/6. For example, std::ranges::iota_view::iterator
is a std::random_access_iterator
but also a stashing iterator. Therefore, I don’t understand why std::bidirectional_iterator
is a sufficient requirement for std::reverse_iterator
to work if the above claim about stashing iterators is true.
Indeed, the following program displays the expected output:
#include <iostream>
#include <ranges>
int main()
{
auto v = std::views::iota(0u, 10'000ul) | std::views::take(10);
for (auto it = std::make_reverse_iterator(v.end());
it != std::make_reverse_iterator(v.begin()); ++it)
std::cout << *it << std::endl;
}
There isn’t really much point in using std::reverse_iterator
with C++20 iterators, since we have std::ranges::reverse_view
, but I’m curious to know whether [forward.iterators]/6 is currently necessary at all.