0

I wanted to introduce the spaceship operator in our Code Base, but we are currently using global templated comparison operators like this:

template <typename L, typename R>
bool operator > (const L& l, const R& r) { return r < l; }

(operator < is usually a member)

When I now try and use operator <=> in a class, my templated operator gets chosen! Why?

In cpp reference the example implementation of the ordering operators are friends and should in every case be superior to a templated function. Example: https://godbolt.org/z/r8qjK6q6f

T.D.
  • 15
  • 4
  • 1
    What is this `(str <=> str) > 0;` on this godbolt? What this should prove? – Marek R Feb 08 '23 at 10:56
  • 1
    Probably you wished to show this problem: https://godbolt.org/z/PWjn81rTv – Marek R Feb 08 '23 at 11:04
  • and why this `bool operator>(const L& l, const R& r)` has two template parameters? If this is reduced to one then there is no conflict: https://godbolt.org/z/sx1v74493 looks like your question lacks some extra information. – Marek R Feb 08 '23 at 11:11
  • 1
    Such a promiscuous `operator>` will likely cause all sorts of problems. [example](https://godbolt.org/z/zddexbYha) – Ted Lyngmo Feb 08 '23 at 11:14
  • You declare `bool operator >` but that function returns `r < l`. That seems odd. Do you want `<` or `>`? – Jesper Juhl Feb 08 '23 at 11:32
  • @JesperJuhl presumably it is a remnant of defining everything in terms of `<` and `!` – Caleth Feb 08 '23 at 11:33
  • 1
    This comparison operator is evil, and whoever wrote it didn't know what they were doing. The reason why it's evil is that it'll be shadowed by other `operator>`s in namespaces (e.g. in `std` it will be shadowed by numerous `std::operator>` for different types, if we still have any after `<=>` became a thing). – HolyBlackCat Feb 08 '23 at 11:34
  • @HolyBlockCat We don't use the standard library in our CodeBase, but thanks for your answer. – T.D. Feb 09 '23 at 12:35
  • @T.D. well you do, because the type of `auto operator<=>` is `std::strong_ordering` – Caleth Feb 09 '23 at 13:17

1 Answers1

2

std::strong_ordering has comparison operators for which one parameter is of unspecified type. It's not clear how they factor in overload resolution, although it is quite probable that they are intentionally the least viable function.

Comparison operators are defined between values of this type and literal ​0​. This supports the expressions a <=> b == 0 or a <=> b < 0 that can be used to convert the result of a three-way comparison operator to a boolean relationship; see std::is_eq, std::is_lt, etc.

These functions are not visible to ordinary unqualified or qualified lookup, and can only be found by argument-dependent lookup when std::strong_ordering is an associated class of the arguments.

The behavior of a program that attempts to compare a strong_ordering with anything other than the integer literal ​0​ is undefined.

Your comparison template is wildly too general. It is implying that anything is > comparable to anything else. Either remove it, or add a requires clause.

template <typename L, typename R>
requires requires (const L& l, const R& r) { r < l; }
bool operator > (const L& l, const R& r) { return r < l; }
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • 1
    *"which are inexpressible in portable C++"* Why is that? – HolyBlackCat Feb 08 '23 at 11:36
  • @HolyBlackCat Afaict, there's no way of defining a type that permits only the literal `0` as a value – Caleth Feb 08 '23 at 11:41
  • I believe you can have a class with a consteval constructor, that causes a compile-time error if you give it any `int` other than `0`. But the standard doesn't even ask for that, it says other comparisons are UB, not ill-formed, so real implementation probably use `nullptr_t` (I hope) or `int` here. – HolyBlackCat Feb 08 '23 at 11:43
  • It would be interesting to know how they did this. To my knowledge a pure template function should be the last to be chosen, before doing implicit conversions. – T.D. Feb 09 '23 at 13:03
  • @T.D. step 1 is order by implicit conversions, step 4 is order by templateness https://en.cppreference.com/w/cpp/language/overload_resolution#Best_viable_function – Caleth Feb 09 '23 at 13:22