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.
The note about stashing iterators is not about l-value vs r-value return from *
, but instead about the multi-pass guarantee.
std::forward_iterator
still has the semantic requirement " ((void)[](auto x){ ++x; }(i), *i)
is equivalent to *i
", which is met by decltype(v.begin())
, but is not (required to be) met by std::filesystem::path::
( const_
) iterator
.
const_iterator
a constant LegacyBidirectionalIterator with avalue_type
of path, except that for dereferenceable iteratorsa
andb
of typepath::iterator
witha == b
, there is no requirement that*a
and*b
are bound to the same object
Nb std::reverse_view
is (for some expressions) defined to return a ranges::subrange<reverse_iterator<...>>
, so it is still relevant.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.