[libcxx-commits] [libcxx] [llvm] [libc++] Implement P3379R0 Constrain `std::expected` equality operators (PR #135759)

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Sat Apr 26 08:27:44 PDT 2025


================
@@ -1139,8 +1140,15 @@ class expected : private __expected_base<_Tp, _Err> {
 
   // [expected.object.eq], equality operators
   template <class _T2, class _E2>
+  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y)
     requires(!is_void_v<_T2>)
-  _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const expected& __x, const expected<_T2, _E2>& __y) {
+#  if _LIBCPP_STD_VER >= 26
+            && requires {
+                 { *__x == *__y } -> __core_convertible_to<bool>;
----------------
frederick-vs-ja wrote:

I've told the reason in https://github.com/llvm/llvm-project/pull/117664#discussion_r1857826166.

`convertible_to` requires both implicit and explicit convertibility, where the standard wording only require the latter. Moreover, due to explicit object member functions and [CWG2813](https://cplusplus.github.io/CWG/issues/2813.html), we can invent a class whose prvalue is implicit convertible to `bool`.

Example ([Godbolt link](https://godbolt.org/z/GYrhdaeYz)):
```C++
#include <type_traits>
#include <concepts>

struct X {
    X() = default;
    X(const X&) = delete;
    X& operator=(const X&) = delete;

    template<class = void>
    constexpr operator bool(this X) { return true; }
    explicit operator bool(this X) = delete;
};

static_assert(!std::is_convertible_v<X, bool>);
static_assert(!std::convertible_to<X, bool>);

constexpr bool b = X{};
```

https://github.com/llvm/llvm-project/pull/135759


More information about the libcxx-commits mailing list