std::sub_match::compare(string_view)
overloadSection: 28.6.8 [re.submatch] Status: New Submitter: Jonathan Wakely Opened: 2018-06-26 Last modified: 2024-10-03
Priority: 3
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]
Previous resolution [SUPERSEDED]:
This wording is relative to N4750.
Change 28.6.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>;// 28.6.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); […] }Change 28.6.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; }; }Change 28.6.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)
.Change sub-clause 28.6.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 anothersub_match
, with astring
, or with a single character. The expressions shown in Table ?? are valid when one of the operands is a typeS
, that is a specialization ofsub_match
, and the other expression is one of:
(?.?) — a value
x
of a typeS
, in which caseSTR(x)
isx.str()
;(?.?) — a value
x
of typebasic_string<S::value_type, T, A>
for any typesT
andA
, in which caseSTR(x)
isbasic_string_view<S::value_type>(x.data(), x.length())
;(?.?) — a value
x
of typebasic_string_view<S::value_type, T>
for any typeT
, in which caseSTR(x)
isbasic_string_view<S::value_type>(x.data(), x.length())
;(?.?) — a value
x
of a type convertible toconst S::value_type*
, in which caseSTR(x)
isbasic_string_view<S::value_type>(x)
;(?.?) — a value
x
of type convertible toS::value_type
, in which caseSTR(x)
isbasic_string_view<S::value_type>(&x, 1)
.
Table ?? — sub_match
comparisonsExpression Return type Operational
semanticss == 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
[2024-10-03; Jonathan rebases the wording on the latest WP]
The proposed resolution has been implemented and tested in libstdc++.
Proposed resolution:
This wording is relative to N4988.
Change 28.6.3 [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>; // 28.6.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 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);
Change 28.6.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; }; }
Change 28.6.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)
.
Change sub-clause 28.6.8.3 [re.submatch.op] as indicated:
32.8.3
sub_match
non-member operators [re.submatch.op]-1- Let
SV(I)
bebasic_string_view<typename iterator_traits<I>::value_type>
and letSM-CAT(I)
becompare_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())) == 0template<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)
.