https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104606

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |ASSIGNED
           Assignee|unassigned at gcc dot gnu.org      |redi at gcc dot gnu.org

--- Comment #12 from Jonathan Wakely <redi at gcc dot gnu.org> ---
std::optional's spaceship operator currently looks like this:

  template<typename _Tp, typename _Up>
    requires (!__is_optional_v<_Up>)
      && three_way_comparable_with<_Tp, _Up>
    constexpr compare_three_way_result_t<_Tp, _Up>
    operator<=>(const optional<_Tp>& __x, const _Up& __v)

As Jakub noted, if we revert the LWG 3566 change it works:

  template<typename _Tp, three_way_comparable_with<_Tp> _Up>
    constexpr compare_three_way_result_t<_Tp, _Up>
    operator<=>(const optional<_Tp>& __x, const _Up& __v)

We can rewrite that to this, which should be exactly equivalent, and it still
works:

  template<typename _Tp, typename _Up>
    requires three_way_comparable_with<_Up, _Tp>
    constexpr compare_three_way_result_t<_Tp, _Up>
    operator<=>(const optional<_Tp>& __x, const _Up& __v)

and then we can add the !is-optional<U> constraint back in:

  template<typename _Tp, typename _Up>
    requires
    (!__is_optional_v<_Up>) &&
      three_way_comparable_with<_Up, _Tp>
    constexpr compare_three_way_result_t<_Tp, _Up>
    operator<=>(const optional<_Tp>& __x, const _Up& __v)

And it still works! The only difference is:
  three_way_comparable_with<_Up, _Tp>
vs
  three_way_comparable_with<_Tp, _Up>

This should not matter, but it does.

So there definitely seems to be a front end bug here, but at least there's an
easy fix for the library.

Reply via email to