Title
There's no std::sub_match::compare(string_view) overload
Status
new
Section
[re.submatch]
Submitter
Jonathan Wakely

Created on 2018-06-26.00:00:00 last changed 2 months ago

Messages

Date: 2024-10-03.19:34:11

Proposed resolution:

This wording is relative to n4988.

  1. Change [re.syn], header <regex> synopsis, as indicated:

      using csub_match = sub_match<const char*>;
      using wcsub_match = sub_match<const wchar_t*>;
      using ssub_match = sub_match<string::const_iterator>;
      using wssub_match = sub_match<wstring::const_iterator>;
    
      // [re.submatch.op], sub_match non-member operators
      template<class BiIter>
        bool operator==(const sub_match<BiIter>& lhs, const sub_match<BiIter>& rhs);
      template<class BiIter>
        bool operator<=>(const sub_match<BiIter>& lhs, const sub_match<BiIter>& rhs);
    
      template<class BiIter, class ST, class SA>
        bool operator==(
          const sub_match<BiIter>& lhs,
          const basic_string<typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);
      template<class BiIter, class ST, class SA>
        bool operator<=>(
          const sub_match<BiIter>& lhs,
          const basic_string<typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);
    
      template<class BiIter, class ST>
        bool operator==(
          const sub_match<BiIter>& lhs,
          const basic_string_view<typename iterator_traits<BiIter>::value_type, ST>& rhs);
      template<class BiIter, class ST>
        bool operator<=>(
          const sub_match<BiIter>& lhs,
          const basic_string_view<typename iterator_traits<BiIter>::value_type, ST>& rhs);
    
      template<class BiIter>
        bool operator==(const sub_match<BiIter>& lhs,
                        const typename iterator_traits<BiIter>::value_type* rhs);
      template<class BiIter>
        bool operator<=>(const sub_match<BiIter>& lhs,
                         const typename iterator_traits<BiIter>::value_type* rhs);
    
      template<class BiIter>
        bool operator==(const sub_match<BiIter>& lhs,
                        const typename iterator_traits<BiIter>::value_type& rhs);
      template<class BiIter>
        bool operator<=>(const sub_match<BiIter>& lhs,
                         const typename iterator_traits<BiIter>::value_type& rhs);
    
      template<class charT, class ST, class BiIter>
        basic_ostream<charT, ST>&
          operator<<(basic_ostream<charT, ST>& os, const sub_match<BiIter>& m);
    
  2. Change [re.submatch], class template sub_match synopsis, as indicated:

    namespace std {
      template<class BidirectionalIterator>
      class sub_match : public pair<BidirectionalIterator, BidirectionalIterator> {
      public:
        using value_type =
          typename iterator_traits<BidirectionalIterator>::value_type;
        […]
        int compare(const sub_match& s) const;
        int compare(const string_type& s) const;
        int compare(const value_type* s) const;
        int compare(basic_string_view<value_type> s) const;
      };
    }
    
  3. Change [re.submatch.members] as indicated:

    int compare(const value_type* s) const;
    

    -7- Returns: str().compare(s).

    int compare(basic_string_view<value_type> s) const;
    

    -?- Returns: str().compare(s).

  4. Change sub-clause [re.submatch.op] as indicated:

    32.8.3 sub_match non-member operators [re.submatch.op]

    -1- Let SV(I) be basic_string_view<typename iterator_traits<I>::value_type> and let SM-CAT(I) be compare_three_way_result_t<basic_string<typename iterator_traits<I>::value_type>SV(I)>

    template<class BiIter>
      bool operator==(const sub_match<BiIter>& lhs, const sub_match<BiIter>& rhs);

    -2- Returns: lhs.compare(rhs) == 0.

    template<class BiIter>
      bool operator<=>(const sub_match<BiIter>& lhs, const sub_match<BiIter>& rhs);

    -3- Returns: static_cast<SM-CAT(BiIter)>(lhs.compare(rhs) <=> 0).

    template<class BiIter, class ST, class SA>
      bool operator==(
        const sub_match<BiIter>& lhs,
        const basic_string<typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);

    -4- Returns: lhs.compare(typename sub_match<BiIter>::string_typeSV(BiIter)(rhs.data(), rhs.size())) == 0.

    template<class BiIter, class ST, class SA>
      auto operator<=>(
        const sub_match<BiIter>& lhs,
        const basic_string<typename iterator_traits<BiIter>::value_type, ST, SA>& rhs);

    -5- Returns:

    static_cast<SM-CAT(BiIter)>(lhs.compare(
        typename sub_match<BiIter>::string_typeSV(BiIter)(rhs.data(), rhs.size()))
          <=> 0
        )
    

    template<class BiIter, class ST>
      bool operator==(
        const sub_match<BiIter>& lhs,
        const basic_string_view<typename iterator_traits<BiIter>::value_type, ST>& rhs);

    -?- Returns: lhs.compare(SV(BiIter)(rhs.data(), rhs.size())) == 0.

    template<class BiIter, class ST>
      auto operator<=>(
        const sub_match<BiIter>& lhs,
        const basic_string_view<typename iterator_traits<BiIter>::value_type, ST>& rhs);

    -?- Returns: static_cast<SM-CAT(BiIter)>(lhs.compare(SV(BiIter)(rhs.data(), rhs.size())) <=> 0) .

Date: 2024-10-15.00:00:00

[ 2024-10-03; Jonathan rebases the wording on the latest WP ]

The proposed resolution has been implemented and tested in libstdc++.

Date: 2018-07-20.00:00:00

[ 2018-07-20 Priority set to 3 after reflector discussion ]

This wording is relative to N4750.

  1. Change [re.syn], header <regex> synopsis, as indicated:

    #include <initializer_list>
    
    namespace std {
      […]
      using csub_match = sub_match<const char*>;
      using wcsub_match = sub_match<const wchar_t*>;
      using ssub_match = sub_match<string::const_iterator>;
      using wssub_match = sub_match<wstring::const_iterator>;
    
      // [re.submatch.op], sub_match non-member operators
      template<class BiIter>
      bool operator==(const sub_match<BiIter>& lhs, const sub_match<BiIter>& rhs);
      […]
      template<class BiIter>
        bool operator>=(const sub_match<BiIter>& lhs,
                       const typename iterator_traits<BiIter>::value_type& rhs);
    
      template<class charT, class ST, class BiIter>
      basic_ostream<charT, ST>&
      operator<<(basic_ostream<charT, ST>& os, const sub_match<BiIter>& m);
      […]
    }
    
  2. Change [re.submatch], class template sub_match synopsis, as indicated:

    namespace std {
      template<class BidirectionalIterator>
      class sub_match : public pair<BidirectionalIterator, BidirectionalIterator> {
      public:
        using value_type =
          typename iterator_traits<BidirectionalIterator>::value_type;
        […]
        int compare(const sub_match& s) const;
        int compare(const string_type& s) const;
        int compare(const value_type* s) const;
        int compare(basic_string_view<value_type> s) const;
      };
    }
    
  3. Change [re.submatch.members] as indicated:

    int compare(const value_type* s) const;
    

    -7- Returns: str().compare(s).

    int compare(basic_string_view<value_type> s) const;
    

    -?- Returns: str().compare(s).

  4. Change sub-clause [re.submatch.op] as indicated:

    31.9.2 sub_match non-member operators [re.submatch.op]

    template<class BiIter>
    bool operator==(const sub_match<BiIter>& lhs, const sub_match<BiIter>& rhs);

    -1- Returns: lhs.compare(rhs) == 0.

    […]
    template<class BiIter>
      bool operator>=(const sub_match<BiIter>& lhs,
        const typename iterator_traits<BiIter>::value_type& rhs);

    -42- Returns: !(lhs < rhs).

    template<class charT, class ST, class BiIter>
      basic_ostream<charT, ST>&
        operator<<(basic_ostream<charT, ST>& os, const sub_match<BiIter>& m);

    -43- Returns: os << m.str().

    Class template sub_match provides overloaded relational operators ([expr.rel]) and equality operators ([expr.eq]) for comparisons with another sub_match, with a string, or with a single character. The expressions shown in Table ?? are valid when one of the operands is a type S, that is a specialization of sub_match, and the other expression is one of:

    1. (?.?) — a value x of a type S, in which case STR(x) is x.str();

    2. (?.?) — a value x of type basic_string<S::value_type, T, A> for any types T and A, in which case STR(x) is basic_string_view<S::value_type>(x.data(), x.length());

    3. (?.?) — a value x of type basic_string_view<S::value_type, T> for any type T, in which case STR(x) is basic_string_view<S::value_type>(x.data(), x.length());

    4. (?.?) — a value x of a type convertible to const S::value_type*, in which case STR(x) is basic_string_view<S::value_type>(x);

    5. (?.?) — a value x of type convertible to S::value_type, in which case STR(x) is basic_string_view<S::value_type>(&x, 1).

    Table ?? — sub_match comparisons
    Expression Return type Operational
    semantics
    s == t bool STR(s).compare(STR(t)) == 0
    s != t bool STR(s).compare(STR(t)) != 0
    s < t bool STR(s).compare(STR(t)) < 0
    s > t bool STR(s).compare(STR(t)) > 0
    s <= t bool STR(s).compare(STR(t)) <= 0
    s >= t bool STR(s).compare(STR(t)) >= 0
Date: 2018-07-15.00:00:00

[ 2018-07-02, Jonathan comments and completes proposed wording ]

To make the relational and equality operators for sub_match support string views I propose specifying the semantics, not adding another 12 overloaded operators to namespace std, in addition to the 42 already there. This allows them to be implemented as "hidden friends" if the implementation so desires, or to retain namespace-scope declaration if backwards compatibility with C++11 - C++17 is preferred.

Date: 2018-06-26.00:00:00

std::sub_match::compare can be called with a basic_string or a pointer to a null-terminated character sequence, but can't be called with a basic_string_view. To compare to a string_view requires either conversion to basic_string (with a potential allocation) or a redundant call to traits_type::length to calculate a length that is already known.

History
Date User Action Args
2024-10-03 19:34:11adminsetmessages: + msg14420
2018-07-20 21:06:57adminsetmessages: + msg10033
2018-07-04 20:07:55adminsetmessages: + msg10010
2018-06-27 18:25:17adminsetmessages: + msg9993
2018-06-26 00:00:00admincreate