[libcxx-commits] [PATCH] D107721: Implement std::pair::operator<=>

Arthur O'Dwyer via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Mon Aug 9 08:01:18 PDT 2021


Quuxplusone requested changes to this revision.
Quuxplusone added a comment.
This revision now requires changes to proceed.

Thanks for working on this! I hope to get D107584 <https://reviews.llvm.org/D107584> landed later today or tomorrow so that you can rebase on it.



================
Comment at: libcxx/include/__compare/__synthesized.h:9-10
+
+#ifndef _LIBCPP___COMPARE___SYNTHESIZED_H
+#define _LIBCPP___COMPARE___SYNTHESIZED_H
+
----------------
This header should be named `__compare/synth_three_way.h` (name after the component, and drop the leading underscores on the filename).


================
Comment at: libcxx/include/__compare/__synthesized.h:24
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_SPACESHIP_OPERATOR)
+
+template <class T, class U>
----------------
Add a comment: `// [expos.only.func]`


================
Comment at: libcxx/include/__compare/__synthesized.h:26
+template <class T, class U>
+constexpr auto __synth_three_way(const T& __t, const U& __u)
+    requires requires {
----------------
`T, U` => `_Tp, _Up`
Also, I'd like to see some discussion (here, and then in the commit message) about why `__synth_three_way` does //not// need to be a lambda object the way it's shown in the Standard. I suspect that since it's used for partly-program-defined types like `std::pair<int, Holder<Incomplete>*>`, the reason may have to do with suppressing ADL... although, no, that doesn't make sense, because we're doing ADL on `__t < __u` on lines 28 and 35 already.


================
Comment at: libcxx/include/__compare/__synthesized.h:42
+template <class T, class U = T>
+using __synth_three_way_result = decltype(__synth_three_way(declval<T&>(), declval<U&>()));
+
----------------
`_VSTD::__synth_three_way` (unless you change it back to a lambda)
also `T, U` => `_Tp, _Up`


================
Comment at: libcxx/include/__utility/pair.h:13-14
 #include <__config>
+#include <__compare/__synthesized.h>
+#include <__compare/common_comparison_category.h>
 #include <__functional/unwrap_ref.h>
----------------
(Once the underscores are removed, these will need to be re-alphabetized.)
Also, `__com < __con`.


================
Comment at: libcxx/include/__utility/pair.h:337-338
+{
+    auto __result = __synth_three_way(__x.first, __y.first);
+    if (__result == 0) return __synth_three_way(__x.second, __y.second);
+    else return __result;
----------------
ADL-proof: `_VSTD::__synth_three_way`, if `__synth_three_way` doesn't become a lambda.

Also, really evil user code could probably detect that you're calling `__result == 0` instead of `__result != 0` (since `__synth_three_way_result<_T1>` could be `Widget`); how about just using the exact implementation from the Standard, two-part `if` and all?

Before addressing this comment, please make the change I suggested in `comparison.pass.cpp`, and re-run your tests. Does my third `NaN` test case actually blow up this implementation?


================
Comment at: libcxx/test/libcxx/compare/synthesized.pass.cpp:11
+
+// template<class T, class U> auto __synth_three_way(T __t, U __u);
+
----------------
Rename the file to `synth_three_way.pass.cpp`. Also I'd recommend putting it under something like
`libcxx/test/libcxx/library/description/conventions/expos.only.func/synth_three_way.pass.cpp`.
(We'd put it next to the tests for `__decay_copy` if we had any, but we don't.)


================
Comment at: libcxx/test/libcxx/compare/synthesized.pass.cpp:21
+int main(int, char**) {
+#if TEST_STD_VER >= 20
+  static_assert(std::__synth_three_way(1, 2) == std::strong_ordering::less);
----------------
This `#if` is true by definition, since the test is unsupported in earlier versions.


================
Comment at: libcxx/test/libcxx/compare/synthesized.pass.cpp:34
+  static_assert(!(NoSpaceship{1} < NoSpaceship{1}), "");
+  static_assert(std::__synth_three_way(NoSpaceship{1}, NoSpaceship{2}) == std::weak_ordering::less);
+  static_assert(std::is_same_v<std::weak_ordering, std::__synth_three_way_result<NoSpaceship, NoSpaceship> >, "");
----------------
Add:
```
static_assert(std::__synth_three_way(NoSpaceship{1}, NoSpaceship{1}) == std::weak_ordering::equivalent);
static_assert(std::__synth_three_way(NoSpaceship{2}, NoSpaceship{1}) == std::weak_ordering::greater);
ASSERT_SAME_TYPE(std::__synth_three_way_result<NoSpaceship, NoSpaceship>, std::weak_ordering);
```
Similarly for the other cases tested below.
Finally, unless someone proves that this is IFNDR, please also test
```
struct CustomSpaceship {
    struct Result { operator std::weak_ordering() const { return std::weak_ordering::equivalent; } };
    Result operator<=>(const CustomSpaceship&) const { return Result(); }
};
ASSERT_SAME_TYPE(decltype(std::__synth_three_way(CustomSpaceship{}, CustomSpaceship{})), CustomSpaceship::Result);
ASSERT_SAME_TYPE(std::__synth_three_way_result<CustomSpaceship, CustomSpaceship>, CustomSpaceship::Result);
```
and make sure you have a test along these lines for `std::pair` as well.

(You might find that `CustomSpaceship` doesn't synth-three-way as written, because it lacks an `operator==`. If so, well, I recommend adding a test for that too.)


================
Comment at: libcxx/test/libcxx/utilities/utility/pairs/pairs.pair/comparison.pass.cpp:41
+  {
+    // Pairs of int and a type with partial_ordering three way comparison should compare with partial ordering.
+    struct WithPartialSpaceship {
----------------
Could you use `double` as your type with partial ordering?
Let's also add a test where the `unordered` result is expected, e.g.
```
std::make_pair(1, 1.0) <=> std::make_pair(2, std::numeric_limits<double>::quiet_NaN())  // expect ::less
std::make_pair(1, 1.0) <=> std::make_pair(1, std::numeric_limits<double>::quiet_NaN())  // expect ::unordered
std::make_pair(1.0, 1) <=> std::make_pair(std::numeric_limits<double>::quiet_NaN(), 2)  // expect ::unordered
```


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D107721/new/

https://reviews.llvm.org/D107721



More information about the libcxx-commits mailing list