const begin
of the join_view
family does not require InnerRng
to be a rangeSection: 25.7.14.2 [range.join.view], 25.7.15.2 [range.join.with.view] Status: Resolved Submitter: Hewill Kang Opened: 2022-05-17 Last modified: 2023-03-23
Priority: 3
View all other issues in [range.join.view].
View all issues with Resolved status.
Discussion:
This is a follow-up of LWG 3599.
Currently, the const
version of join_view::begin
has the following constraints
constexpr auto begin() const requires input_range<const V> && is_reference_v<range_reference_t<const V>> { return iterator<true>{*this, ranges::begin(base_)}; }
which only requires InnerRng
to be a reference type, but in some cases, InnerRng
may not be a range
. Consider
#include <ranges> int main() { auto r = std::views::iota(0, 5) | std::views::split(1); auto s = std::views::single(r); auto j = s | std::views::join; auto f = j.front(); }
The reference type of single_view
is const split_view&
, which only has the non-const
version of begin
, which will cause view_interface
's const front
to be incorrectly
instantiated, making r.front()
unnecessarily ill-formed.
We should add this check for join_view
's const begin
, as well as join_with_view
.
[2022-06-21; Reflector poll]
Set priority to 3 after reflector poll.
Previous resolution [SUPERSEDED]:
This wording is relative to N4910.
Modify 25.7.14.2 [range.join.view], class template
join_view
synopsis, as indicated:namespace std::ranges { […] template<input_range V> requires view<V> && input_range<range_reference_t<V>> class join_view : public view_interface<join_view<V>> { private: […] public: […] constexpr auto begin() { […] } constexpr auto begin() const requires input_range<const V> && input_range<range_reference_t<const V>> && is_reference_v<range_reference_t<const V>> { return iterator<true>{*this, ranges::begin(base_)}; } constexpr auto end() { […] } constexpr auto end() const requires input_range<const V> && input_range<range_reference_t<const V>> && is_reference_v<range_reference_t<const V>> { if constexpr (forward_range<const V> && forward_range<range_reference_t<const V>> && common_range<const V> && common_range<range_reference_t<const V>>) return iterator<true>{*this, ranges::end(base_)}; else return sentinel<true>{*this}; } }; […] }Modify 25.7.15.2 [range.join.with.view], class template
join_with_view
synopsis, as indicated:namespace std::ranges { […] template<input_range V, forward_range Pattern> requires view<V> && input_range<range_reference_t<V>> && view<Pattern> && compatible-joinable-ranges<range_reference_t<V>, Pattern> class join_with_view : public view_interface<join_with_view<V, Pattern>> { private: […] public: […] constexpr auto begin() { […] } constexpr auto begin() const requires input_range<const V> && forward_range<const Pattern> && input_range<range_reference_t<const V>> && is_reference_v<range_reference_t<const V>> { return iterator<true>{*this, ranges::begin(base_)}; } constexpr auto end() { […] } constexpr auto end() const requires input_range<const V> && forward_range<const Pattern> && input_range<range_reference_t<const V>> && is_reference_v<range_reference_t<const V>> { using InnerConstRng = range_reference_t<const V>; if constexpr (forward_range<const V> && forward_range<InnerConstRng> && common_range<const V> && common_range<InnerConstRng>) return iterator<true>{*this, ranges::end(base_)}; else return sentinel<true>{*this}; } }; […] }
[2023-03-22 Resolved by the adoption of P2770R0 in Issaquah. Status changed: New → Resolved.]
Proposed resolution: