简体   繁体   中英

Does std::reverse_iterator work with adapted ranges?

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 iterator i , the relationship &*r == &*(i-1) is always true (as long as r 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 is std::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 a LegacyBidirectionalIterator or model bidirectional_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 a value_type of path, except that for dereferenceable iterators a and b of type path::iterator with a == 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM