Created on 2023-06-28.00:00:00 last changed 12 months ago
Proposed resolution:
This wording is relative to N4950.
Modify [iterator.synopsis], header <iterator> synopsis, as indicated:
[…] template<indirectly_readable T> using iter_common_reference_t = // freestanding common_reference_t<iter_reference_t<T>&&, indirect-value-t<T>>; […]
Modify [const.iterators.alias] as indicated:
template<indirectly_readable It> using iter_const_reference_t = common_reference_t<const iter_value_t<It>&&, iter_reference_t<It>&&>;
Modify [const.iterators.iterator] as indicated:
namespace std { template<class I> concept not-a-const-iterator = see below; // exposition only template<indirectly_readable I> using iter-const-rvalue-reference-t = // exposition only common_reference_t<const iter_value_t<I>&&, iter_rvalue_reference_t<I>&&>; […] };
[ 2023-10-30; Reflector poll ]
Set priority to 3 after reflector poll.
"NAD - This can easily lead to dangling references. This only matters if
iter_reference_t
isn't a language reference type,
and the change causes common_reference
to produce
a language reference type. So binding to the common reference requires
a temporary. That's not going to work if the type is used as a return type
(as the const-cases are).
As written I think it also causes significant damage to constant-iterator."
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.History | |||
---|---|---|---|
Date | User | Action | Args |
2023-10-30 16:39:42 | admin | set | messages: + msg13780 |
2023-07-02 08:40:36 | admin | set | messages: + msg13674 |
2023-06-28 00:00:00 | admin | create |