join_view::iterator::operator->()
is bogusSection: 25.7.14.3 [range.join.iterator] Status: C++23 Submitter: Michael Schellenberger Costa Opened: 2020-11-15 Last modified: 2023-11-22
Priority: 0
View all other issues in [range.join.iterator].
View all issues with C++23 status.
Discussion:
There seems to be a copy & paste error in the join_view::iterator::operator->()
specification. According to 25.7.14.3 [range.join.iterator] p8 it is specified as:
constexpr iterator_t<Base> operator->() const requires has-arrow<iterator_t<Base>> && copyable<iterator_t<Base>>;-8- Effects: Equivalent to
return inner_;
Now inner_
is of type iterator_t<range_reference_t<Base>>
. So it
is unclear how that should be converted to iterator_t<Base>
, or why the
constraints concern the outer iterator type iterator_t<Base>
. On the other hand
returning outer_
would not make any sense here.
iterator_t<Base>
with
iterator_t<range_reference_t<Base>>
so that the new specification would
read
constexpr iterator_t<range_reference_t<Base>> operator->() const requires has-arrow<iterator_t<range_reference_t<Base>>> && copyable<iterator_t<range_reference_t<Base>>>;-8- Effects: Equivalent to
return inner_;
Generally it would help readability of the specification a lot if we would introduce some exposition only aliases:
using OuterIter = iterator_t<Base>; //exposition-only using InnerIter = iterator_t<range_reference_t<Base>> //exposition-only
and use them throughout join_view::iterator
.
[2020-11-21; Reflector prioritization]
Set priority to 0 and status to Tentatively Ready after six votes in favour during reflector discussions.
[2021-02-26 Approved at February 2021 virtual plenary. Status changed: Tentatively Ready → WP.]
Proposed resolution:
This wording is relative to N4868.
Modify 25.7.14.3 [range.join.iterator], class template join_view::iterator
synopsis,
as indicated:
template<input_range V> requires view<V> && input_range<range_reference_t<V>> && (is_reference_v<range_reference_t<V>> || view<range_value_t<V>>) struct join_view<V>::iterator { private: using Parent = // exposition only conditional_t<Const, const join_view, join_view>; using Base = conditional_t<Const, const V, V>; // exposition only using OuterIter = iterator_t<Base>; //exposition-only using InnerIter = iterator_t<range_reference_t<Base>> //exposition-only static constexpr bool ref-is-glvalue = // exposition only is_reference_v<range_reference_t<Base>>; OuterIteriterator_t<Base>outer_ = OuterIteriterator_t<Base>(); // exposition only InnerIteriterator_t<range_reference_t<Base>>inner_ = // exposition only InnerIteriterator_t<range_reference_t<Base>>(); Parent* parent_ = nullptr; // exposition only constexpr void satisfy(); // exposition only public: […] iterator() = default; constexpr iterator(Parent& parent, OuterIteriterator_t<Base>outer); constexpr iterator(iterator<!Const> i) requires Const && convertible_to<iterator_t<V>, OuterIteriterator_t<Base>> && convertible_to<iterator_t<InnerRng>, InnerIteriterator_t<range_reference_t<Base>>>; constexpr decltype(auto) operator*() const { return *inner_; } constexpr InnerIteriterator_t<Base>operator->() const requires has-arrow<InnerIteriterator_t<Base>> && copyable<InnerIteriterator_t<Base>>; constexpr iterator& operator++(); […][…]
constexpr void satisfy(); // exposition only-5- Effects: Equivalent to:
[…] if constexpr (ref-is-glvalue) inner_ = InnerIteriterator_t<range_reference_t<Base>>();constexpr iterator(Parent& parent, OuterIteriterator_t<Base>outer);[…]
constexpr iterator(iterator<!Const> i) requires Const && convertible_to<iterator_t<V>, OuterIteriterator_t<Base>> && convertible_to<iterator_t<InnerRng>, InnerIteriterator_t<range_reference_t<Base>>>;[…]
constexpr InnerIteriterator_t<Base>operator->() const requires has-arrow<InnerIteriterator_t<Base>> && copyable<InnerIteriterator_t<Base>>;-8- Effects: Equivalent to
return inner_;