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

            Bug ID: 106676
           Summary: [C++20] Automatic iterator_category detection
                    misbehaves when `::reference` is an rvalue reference,
                    refuses to accept a forward iterator
           Product: gcc
           Version: 12.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: iamsupermouse at mail dot ru
  Target Milestone: ---

Since C++20, `std::iterator_traits` can auto-detect `::iterator_category`, if
the iterator doesn't set it.

Forward iterators require `::reference` (aka the return type of `operator*`) to
be a reference (any reference), but libstdc++ only accepts lvalue references
here.

Example:

    #include <iterator>
    #include <type_traits>

    template <typename T>
    struct A
    {
        using value_type = std::remove_cvref_t<T>;
        using difference_type = int;
        T operator*() const;
        A &operator++();
        A operator++(int);
        bool operator==(const A &) const;
    };

    // Ok.
    static_assert(std::is_same_v<std::iterator_traits<A<int
&>>::iterator_category, std::forward_iterator_tag>);
    // Should pass but fails, the category is `std::input_iterator_tag`.
    static_assert(std::is_same_v<std::iterator_traits<A<int
&&>>::iterator_category, std::forward_iterator_tag>);

I blame this on cppreference, which used to incorrectly say that only lvalue
references are allowed there. It was fixed since then.

See https://eel.is/c++draft/iterators#forward.iterators-1.3. Also see
https://cplusplus.github.io/LWG/issue1211 (from 2009), which was resolved by
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3066.html (in 2010).

This was discussed on SO: https://stackoverflow.com/q/73353152

libc++ and MSVC's standard library share the exact same bug.

This was tested on GCC 12.1 and on trunk (13.0.0).

Reply via email to