https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96070

            Bug ID: 96070
           Summary: std::views::* won't work with non-legacy iterators
           Product: gcc
           Version: 11.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: gcc-bugs at marehr dot dialup.fu-berlin.de
  Target Milestone: ---

Hi gcc-team,

not long ago a filed a bug-report[1] that
`std::ranges::basic_istream_view::iterator` has no `std::iterator_traits`
entry. 

> Your mistake is thinking that the iterators of views are like the iterators 
> you're used to.

It seems that not only I had that problem, because this has some interesting
consequences for the standard, for example the
`std::ranges::filter_view::iterator` is described as [2]:

> 3 iterator​::​iterator_­category is defined as follows:
> (3.1) Let C denote the type 
> iterator_­traits<iterator_­t<V>>​::​iterator_­category.
> (3.2) If C models derived_­from<bidirectional_­iterator_­tag>, then 
> iterator_­category denotes bidirectional_­iterator_­tag.
> (3.3) Otherwise, if C models derived_­from<forward_­iterator_­tag>, then 
> iterator_­category denotes forward_­iterator_­tag.
> (3.4) Otherwise, iterator_­category denotes C.

This assumes that `iterator_­traits<iterator_­t<V>>​::​iterator_­category` is
defined which is not true for all iterators, like
`std::ranges::basic_istream_view::iterator`.

A quick check with the gcc stdlib implementation:

```c++
#include <iostream>
#include <ranges>
#include <vector>

int main()
{
    // using input_view_t = std::vector<int> &; // works
    using input_view_t = std::ranges::basic_istream_view<char, char,
std::char_traits<char>>; // does not work

    auto accept_all = [](auto &&){return true;};
    using filter_input_view_t = decltype(std::declval<input_view_t>() |
std::views::filter(accept_all));
    using filter_iterator_t = std::ranges::iterator_t<filter_input_view_t>;
}
```

https://godbolt.org/z/Uozktw

And yes it does not work.

Since I don't know of a generic way to conditionally include/exclude `using
iterator_category = some_tag`, I think the easiest way would to allow
`iterator_category = void`.

We would need to change the behaviour of `std::iterator_traits`. We should not
only check whether all 4 members are available, but also that
`iterator_category` is at least an input_iterator_tag or an
output_iterator_tag. Or alternatively check that `iterator_category` is
non-void.

I don't know how to create a LWG issue and if this problem was already
reported, but I hope you can create one like in my last finding [3].

If this defect was not reported yet, it would be nice to at least link back to
this issue and not just write "A user reported that this doesn't compile: ".

[1] - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94674
[2] - https://eel.is/c++draft/range.filter.iterator#3
[3] - https://cplusplus.github.io/LWG/issue3448

Reply via email to