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

1

6

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?

Toughie answered 15/8, 2020 at 15:44 Comment(8)
There's not a single mention of nullptr in your posted code..Blackburn
Your IDE is not a C++ compiler. Only an actual compiler can fully understand C++ code. Especially the newer versions of C++. It is not surprising that an IDE misparses C++ code.Rolandorolandson
@JesperJuhl "and yields identical results to both the 0 and the nullptr version." - I meant that if we actually replace if (const auto result = name <=> p.name; result != 0) with if (const auto result = name <=> p.name; result != nullptr), the code compiles and yields the expected results.Toughie
@SamVarshavchik, The error comes from clang-tidy (which still isn't a compiler, but it's pretty close where it matters). The IDE is simply handling the task of running clang-tidy and conveying the results.Stretcher
@SamVarshavchik an actualy compiler (g++ 10.1.0) accepted and successfully compiled the code with nullptr instead of 0. Barry covered the topic in his answer pretty well. It's not about parsing, it's about clang-tidy and actualy compilers (suggesting) and accepting this.Toughie
clang-tidy is also not a C++ compiler. It borrows some code from a C++ compiler, but it is not a complete C++ compiler, in of itself.Rolandorolandson
@SamVarshavchik: "clang-tidy is also not a C++ compiler. It borrows some code from a C++ compiler, but it is not a complete C++ compiler, in of itself." I don't know what that has to do with this issue. Clang-tidy is not saying that the code won't compile or is invalid or even broken; it's offering suggestions as to what it thinks is a better way to write that code. That's kind of it's job; it's definitely wrong in this case, but that is what it's trying to do.Battement
As for "old" operator <, auto operator <=> (const person& p) const { return std::tie(name, surname) <=> std::tie(p.name, p.surname); ) :) (or even = default; here ;) )Garrick
S
11

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.

Stevens answered 15/8, 2020 at 15:48 Comment(3)
So it seems like an implementation detail that fooled clang-tidy. Thanks, that makes perfect sense.Toughie
Similarly, virtual void foo() = nullptr; is also no bueno.Latrena
@Latrena Sure, but that's not really the same thing - that's the grammar requiring 0 while this is more or less an implementation hack.Stevens

© 2022 - 2024 — McMap. All rights reserved.