Title
The const begin of the join_view family does not require InnerRng to be a range
Status
resolved
Section
[range.join.view][range.join.with.view]
Submitter
Hewill Kang

Created on 2022-05-17.00:00:00 last changed 20 months ago

Messages

Date: 2023-03-22.00:00:00

[ 2023-03-22 Resolved by the adoption of P2770R0 in Issaquah. Status changed: New → Resolved. ]

Date: 2022-06-15.00:00:00

[ 2022-06-21; Reflector poll ]

Set priority to 3 after reflector poll.

This wording is relative to N4910.

  1. Modify [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};
        }
      };
    
      […]
    
    }
    
  2. Modify [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};
        }
      };
    
      […]
    
    }
    
Date: 2022-05-17.00:00:00

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.

History
Date User Action Args
2023-03-23 11:42:08adminsetstatus: new -> resolved
2022-06-21 11:46:11adminsetmessages: + msg12511
2022-05-21 11:42:57adminsetmessages: + msg12472
2022-05-17 00:00:00admincreate