Search code examples
c++c++20nullptrspaceship-operator

What does comparing the result of the three-way comparison operator with nullptr do?


Given the example from cppreference on <=>, we can simplify the example code to:

struct person {
    std::string name;
    std::string surname;

    auto operator <=> (const person& p) const {
        if (const auto result = name <=> p.name; result != 0) {
            return result;
        } else {
            return surname <=> p.surname;
        }
    }
};

But my IDE (CLion 2020.2), via clang-tidy, warns that result != 0 should actually be result != nullptr. I didn't know that we can compare std::###_ordering with nullptr. Cpprefence also claims that we should rather compare it with literal 0. There is nothing about nullptr there.

This code:

int main() {
    person p1{"ccc", "vvv"};
    person p2{"aaa", "zzz"};

    std::cout << (p1 < p2);
}

compiles (GCC 10.1.0, Rev3, Built by MSYS2 project) and yields identical results to both the 0 and the nullptr version.


However, my IDE also warns me that I should "Clang-Tidy: Use nullptr" with p1 < p2. By applying the "fix", the code changes to std::cout << (p1 nullptr p2); which, well, doesn't compile. It hints that it may be a bug in clang-tidy, but it doesn't explain why we can compare the orderings with nullptr. Why we can, why does it work and why would we want that?


Solution

  • But my IDE (CLion 2020.2), via clang-tidy, warns that result != 0 should actually be result != nullptr.

    This is wrong. It should be result != 0. The comparison categories are specified to only be comparable against the literal 0.

    The check likely comes from the fact that the only real way to implement comparing against the literal 0 in C++20 is to take an argument whose type is some unspecified pointer or function pointer to pointer to member - and clang-tidy likely flags any 0 that you provide as an argument to a pointer as something that should be nullptr. Most of the time, this is correct. Just not specifically here. And indeed, if you write result != nullptr it probably will compile - but that's wrong and you should not do it.

    This is a clang-tidy problem, it needs to understand that for comparison categories, it should not flag the use of literal 0 in this way.