Title
compatible-joinable-ranges is underconstrained
Status
new
Section
[range.join.with.view]
Submitter
Hewill Kang

Created on 2024-04-21.00:00:00 last changed 1 week ago

Messages

Date: 2024-04-27.12:57:29

Proposed resolution:

This wording is relative to N4981.

  1. Modify [ranges.syn] as indicated:

    #include <compare>              // see [compare.syn]
    #include <initializer_list>     // see [initializer.list.syn]
    #include <iterator>             // see [iterator.synopsis]
    
    namespace std::ranges {
      […]
      // [range.join.with], join with view
      template<class R, class P>
        concept compatible-joinable-ranges = see below; // exposition only
    
      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>
              see below
      class join_with_view;                                                             // freestanding
      […]
    }
    
  2. Modify [range.join.with.view] as indicated:

    namespace std::ranges {
      template<class R, class P>
        concept compatible-joinable-ranges =            // exposition only
            common_with<range_value_t<R>, range_value_t<P>> &&
            common_reference_with<range_reference_t<R>, range_reference_t<P>> &&
            common_reference_with<range_rvalue_reference_t<R>, range_rvalue_reference_t<P>>;
      
      […]
    
      template<input_range V, forward_range Pattern>
        requires view<V> && input_range<range_reference_t<V>>
              && view<Pattern>
              && compatible-joinable-rangesconcatable<range_reference_t<V>, Pattern>
      class join_with_view : public view_interface<join_with_view<V, Pattern>> {
        […]
        constexpr auto begin() const
          requires forward_range<const V> &&
                   forward_range<const Pattern> &&
                   is_reference_v<range_reference_t<const V>> &&
                   input_range<range_reference_t<const V>> &&
                   concatable<range_reference_t<const V>, const Pattern> {
          return iterator<true>{*this, ranges::begin(base_)};
        }
        […]
        constexpr auto end() const
          requires forward_range<const V> && forward_range<const Pattern> &&
                   is_reference_v<range_reference_t<const V>> &&
                   input_range<range_reference_t<const V>> &&
                   concatable<range_reference_t<const V>, const Pattern> {
          […]
        }
      };
    }
    
  3. Modify [range.join.with.iterator] 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-rangesconcatable<range_reference_t<V>, Pattern>
      template<bool Const>
      class join_with_view<V, Pattern>::iterator {
        […]
      };
    }
    
  4. Modify [range.join.with.sentinel] 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-rangesconcatable<range_reference_t<V>, Pattern>
      template<bool Const>
      class join_with_view<V, Pattern>::sentinel {
        […]
      };
    }
    
Date: 2024-04-15.00:00:00

[ 2024-04-24; Hewill Kang provides improved wording ]

Date: 2024-04-27.12:57:29

join_with_view requires the value type, reference and rvalue reference of the inner range and pattern range to share common (reference) types through compatible-joinable-ranges.

However, unlike what concat_view and generator do, this concept only requires that these three types be valid and does not further check the relationship between them to be compatible with the indirectly_readable requirement for input_iterator. This results in a validly-constructed join_with_view that may not model input_range, which seems unintended.

The proposed resolution aliases compatible-joinable-ranges to concatable i.e. specialization for two ranges to fully constrain, and I believe this could also be a better fit for LWG 3971.

This wording is relative to N4981.

  1. Modify [range.join.with.view] as indicated:

    namespace std::ranges {
      template<class R, class P>
        concept compatible-joinable-ranges = concatable<R, P>;  // exposition only
            common_with<range_value_t<R>, range_value_t<P>> &&
            common_reference_with<range_reference_t<R>, range_reference_t<P>> &&
            common_reference_with<range_rvalue_reference_t<R>, range_rvalue_reference_t<P>>;
      
      […]
    }
    
History
Date User Action Args
2024-04-27 12:57:29adminsetmessages: + msg14077
2024-04-21 14:03:42adminsetmessages: + msg14071
2024-04-21 00:00:00admincreate