Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::variant comparison with std::nullptr_t inside

Tags:

c++

c++17

My problem can be summarised in following code

#include <variant>

int main()
{
    using V = std::variant<int, std::nullptr_t>;
    V a = 0;
    V b = nullptr;

    a < b;
}

I want to have variant with std::nullptr_t inside and I want to be able to compare such variants. It was working on Visual Studio 2018 (version 16.1.X), but it won't compile on version 16.3.1. I thought that this is a bug in the compiler, but I'm not sure now. I cannot find anything about std::nullptr_t supporting comparison operators and even GCC and Clang seems to disagree. Should it be working, or not? Also, if no is the correct answer, is there a way to make it work? Defining of the operator for std::nullptr_t doesn't seem to work.

inline bool operator<(std::nullptr_t, std::nullptr_t)
{
    return false;
}

As defining relational operators can be done only on class parameter.

Thanks.

like image 875
koscelansky Avatar asked Mar 04 '23 09:03

koscelansky


1 Answers

The type std::nullptr_t does not have any relational operators defined for it. It is only equality-comparable (that is nullptr == nullptr is valid and true, but nullptr < nullptr is ill-formed). You could argue that this is a defect, and we could define the relational operators such that nullptr < nullptr is false and nullptr <= nullptr is true, etc. But that is the way it is.

Using < on variant<Ts...> requires < to be a valid operation on each type in Ts..., which is not the case in your example, hence a < b is ill-formed. This isn't a bug in any of the compilers or the libraries, it's the expected behavior.


The only way to make < work here is to provide types that actually have a < - that is, wrap std::nullptr_t in some other type that actually is ordered. Do you need specifically std::nullptr_t? Maybe std::monostate, which has all six comparisons, is a better choice?

like image 172
Barry Avatar answered Mar 14 '23 23:03

Barry