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).