This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofWP status.
std::basic_string_view comparison operators are overspecifiedSection: 27.3.2[string.view.synop]Status:WPSubmitter: Giuseppe D'AngeloOpened: 2023-06-21Last modified: 2024-04-02
Priority:Not Prioritized
View all issues withWP status.
Discussion:
The<string_view> synopsis in 27.3.2[string.view.synop] has these signaturesforoperator== andoperator<=>:
//27.3.4[string.view.comparison], non-member comparison functionstemplate<class charT, class traits> constexpr bool operator==(basic_string_view<charT, traits> x, basic_string_view<charT, traits> y) noexcept;template<class charT, class traits> constexpr see below operator<=>(basic_string_view<charT, traits> x, basic_string_view<charT, traits> y) noexcept;//see 27.3.4[string.view.comparison], sufficient additional overloads of comparison functions
In 27.3.4[string.view.comparison], paragraph 1 states that "Implementationsshall provide sufficient additional overloads" so that all comparisonsbetween abasic_string_view<C, T> object and an object of a typeconvertible tobasic_string_view<C, T> work (with the reasonablesemantics).
operator==:template<class charT, class traits> constexpr bool operator==(basic_string_view<charT, traits> lhs, basic_string_view<charT, traits> rhs) noexcept { return lhs.compare(rhs) == 0; }template<class charT, class traits> constexpr bool operator==(basic_string_view<charT, traits> lhs, type_identity_t<basic_string_view<charT, traits>> rhs) noexcept { return lhs.compare(rhs) == 0; }With the current semantics of rewritten candidates for the comparisonoperators, it is however superfluous to actually specify both overloads(the same applies foroperator<=>).
type_identity_t) is indeed necessary toimplement the "sufficient additional overloads" part of 27.3.4[string.view.comparison], but it is also sufficient, as all the following casessv == sv
sv ==convertible_to_sv
convertible_to_sv == sv
can in fact use it (directly, or after being rewritten e.g. with thearguments swapped).
The reason why we still do have both operators seems to be historical;there is an explanation offeredhere by Barry Revzin.Basically, there were three overloads before a bunch of papers regardingoperator<=> andoperator== were merged:operator==(bsv,bsv) to deal withsv == sv;
operator==(bsv, type_identity_t<bsv>) and
operator==(type_identity_t<bsv>,bsv) to deal withsv ==convertible_to_sv and vice versa.
Overload (1) was necessary because with only (2) and (3) a call likesv == sv would otherwise be ambiguous. With the adoption of the rewritingrules, overload (3) has been dropped, without realizing that overload(1) would then become redundant.
type_identity_t.[Kona 2023-11-10; move to Ready]
Editorial issue6324provides the changes as a pull request to the draft.
[Tokyo 2024-03-23; Status changed: Voting → WP.]
Proposed resolution:
This wording is relative toN4950.
Modify 27.3.2[string.view.synop], header<string_view> synopsis, as indicated:
[…]//27.3.4[string.view.comparison], non-member comparison functionstemplate<class charT, class traits> constexpr bool operator==(basic_string_view<charT, traits> x,type_identity_t<basic_string_view<charT, traits>> y) noexcept;template<class charT, class traits> constexprsee below operator<=>(basic_string_view<charT, traits> x,type_identity_t<basic_string_view<charT, traits>> y) noexcept;//see 27.3.4[string.view.comparison], sufficient additional overloads of comparison functions[…]
Modify 27.3.4[string.view.comparison] as indicated:
-1- LetSbebasic_string_view<charT, traits>, andsvbe an instance ofS. Implementations shall provide sufficient additional overloads markedconstexprandnoexceptso that an objecttwith an implicit conversion toScan be compared according to Table 81 [tab:string.view.comparison.overloads].
Table 81: Additionalbasic_string_viewcomparison overloads [tab:string.view.comparison.overloads]ExpressionEquivalent tot == svS(t) == svsv == tsv == S(t)t != svS(t) != svsv != tsv != S(t)t < svS(t) < svsv < tsv < S(t)t > svS(t) > svsv > tsv > S(t)t <= svS(t) <= svsv <= tsv <= S(t)t >= svS(t) >= svsv >= tsv >= S(t)t <=> svS(t) <=> svsv <=> tsv <=> S(t)
[Example 1: A sample conforming implementation foroperator==would be:template<class charT, class traits> constexpr bool operator==(basic_string_view<charT, traits> lhs, basic_string_view<charT, traits> rhs) noexcept { return lhs.compare(rhs) == 0; }template<class charT, class traits> constexpr bool operator==(basic_string_view<charT, traits> lhs, type_identity_t<basic_string_view<charT, traits>> rhs) noexcept { return lhs.compare(rhs) == 0; }
—end example]template<class charT, class traits> constexpr bool operator==(basic_string_view<charT, traits> lhs,type_identity_t<basic_string_view<charT, traits>> rhs) noexcept;-2-Returns:
lhs.compare(rhs) == 0.template<class charT, class traits> constexprsee below operator<=>(basic_string_view<charT, traits> lhs,type_identity_t<basic_string_view<charT, traits>> rhs) noexcept;-3- Let
-4-Mandates:Rdenote the typetraits::comparison_categoryif thatqualified-id is valid and denotes atype (13.10.3[temp.deduct]), otherwiseRisweak_ordering.Rdenotes a comparison category type (17.12.2[cmp.categories]).-5-Returns:static_cast<R>(lhs.compare(rhs) <=> 0). [Note: The usage oftype_identity_tas parameter ensures that an object of typebasic_string_view<charT, traits>can always be compared with an object of a typeTwith an implicit conversion tobasic_string_view<charT, traits>, and vice versa, as per 12.2.2.3[over.match.oper]. —end note]