Date
2023-07-02.09:55:17
Message id
13673

Content

The indirectly_readable concept ([iterator.concept.readable]) requires iter_reference_t<In>&& and iter_value_t<In>& to model common_reference_with, which ensures that the input iterator always has a common reference type.

However, iter_common_reference_t for computing such types is defined as common_reference_t<iter_reference_t<T>, indirect-value-t<T>>.

It is unclear why the formula here drop the && part of iter_reference_t<In>, but theoretically it is not completely equivalent to the former, for example:

#include <iterator>

struct Ref {
  Ref(const Ref&) = delete;
};

struct Val {
  operator const Ref&() const &;
};

struct I {
  using value_type = Val;
  using difference_type = int;
  Ref operator*() const;
  I& operator++();
  I operator++(int);
};

static_assert(std::input_iterator<I>);
using reference  = std::iter_reference_t<I>;
using value_type = std::iter_value_t<I>;
static_assert(std::same_as<std::common_reference_t<reference&&, value_type&>, const Ref&>);
static_assert(std::same_as<std::common_reference_t<reference  , value_type&>,       Ref >);

std::iter_value_t<I> val;
std::iter_common_reference_t<I> cr = val; // failed

In the above example, input_iterator ensures that the iterator's lvalue value type and rvalue reference type can be bound to its common reference type, namely const Ref&, but the type calculated by iter_common_reference_t is Ref, which cannot be bound by both.

The proposed resolution re-adds the && to iter_reference_t<In> in formulas of similar form to conform to the definition of indirectly_readable.