Title
join_view incorrectly stores inner range
Status
new
Section
[range.join.view][range.join.with.view]
Submitter
Hewill Kang

Created on 2025-03-06.00:00:00 last changed 3 weeks ago

Messages

Date: 2025-03-09.10:46:08

Proposed resolution:

This wording is relative to N5001.

  1. Modify [range.join.view] 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:
        using InnerRng = range_reference_t<V>;                  // exposition only
        […]
        non-propagating-cache<remove_cv_t<InnerRng>> inner_;    // exposition only, present only
                                                                // if is_reference_v<InnerRng> is false
    
      public:
        […]
      };
      […]
    }
    
  2. Modify [range.join.with.view] as indicated:

    namespace std::ranges {
      […]
      template<input_range V, forward_range Pattern>
        requires view<V> && input_range<range_reference_t<V>>
              && view<Pattern>
              && concatable<range_reference_t<V>, Pattern>
      class join_with_view : public view_interface<join_with_view<V, Pattern>> {
        using InnerRng = range_reference_t<V>;                 // exposition only
        […]
        non-propagating-cache<remove_cv_t<InnerRng>> inner_;   // exposition only, present only
                                                               // if is_reference_v<InnerRng> is false
    
        […]
      public:
        […]
      };
      […]
    }
    
    
Date: 2025-03-06.00:00:00

When the inner range is a prvalue, join_view removes its cv-qualifiers and stores it in the propagating-cache, which is not quite right as the inner range may only be const-iterable (demo):

#include <ranges>

struct R {
  int* begin() = delete;
  int* end() = delete;
  const int* begin() const;
  const int* end() const;
};

int main() {
  auto r = std::views::iota(0, 5)
         | std::views::transform([](int) -> const R { return {}; })
         | std::views::join;
  auto b = r.begin(); // hard error
}

The proposed resolution preserves the inner range's original qualifiers, which is consistent with how cache_latest_view stores the reference when it is a prvalue. The same goes for join_with_view.

History
Date User Action Args
2025-03-09 10:46:08adminsetmessages: + msg14673
2025-03-06 00:00:00admincreate