Search code examples
c++clangstandardsc++20spaceship-operator

Why does global spaceship operator not behave as expected?


#include <compare>
#include <forward_list>

template<typename T>
struct A
{
    std::forward_list<T> l;
};

template<typename T>
auto operator<=>(const A<T>& lhs, const A<T>& rhs)
{
    return lhs.l <=> rhs.l;
}

int main()
{
    std::forward_list<int>{} < std::forward_list<int>{}; // ok

    A<int>{} < A<int>{}; // error
}

Compiled with clang++ -std=c++20 -stdlib=libc++ main.cpp and error messages:

main.cpp:13:18: error: invalid operands to binary expression ('const std::forward_list<int>' and 'const std::forward_list<int>')
    return lhs.l <=> rhs.l;
           ~~~~~ ^   ~~~~~
main.cpp:20:14: note: in instantiation of function template specialization 'operator<=><int>' requested here
    A<int>{} < A<int>{}; // error

Why does global spaceship operator not behave as expected?


Solution

  • It does not seem that libc++ (or any of the standard libraries) implements the spaceship operator library additions completely yet.

    See here for libc++ and here for a compiled table at cppreference.com. The relevant paper adding the operator<=> to std::forward_list is P1614.

    If you look at libc++'s source code for std::forward_list here, you see that there is no mention of operator<=> yet and the other secondary comparison operators are still defined unconditionally (which should not be the case in C++20).

    std::forward_list<int>{} < std::forward_list<int>{}; compiles because it uses operator<, not operator<=>. If you tried std::forward_list<int>{} <=> std::forward_list<int>{} directly, it would fail as well (in the current state of libc++).