This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

### 3126. There's no `std::sub_match::compare(string_view)` overload

Section: 30.8 [re.submatch] Status: New Submitter: Jonathan Wakely Opened: 2018-06-26 Last modified: 2020-09-06

Priority: 3

View other active issues in [re.submatch].

View all other issues in [re.submatch].

View all issues with New status.

Discussion:

`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.

[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.

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

Proposed resolution:

This wording is relative to N4750.

1. Change 30.3 [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>;

   >       // 30.8.3 [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 30.8 [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 30.8.2 [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 30.8.3 [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 (7.6.9 [expr.rel]) and equality operators (7.6.10 [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`