std::variant 内部与 std::nullptr_t 的比较

4

我的问题可以用以下代码总结:

#include <variant>

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

    a < b;
}

我想要一个包含std::nullptr_t的变量,并且我希望能够比较这样的变量。它在Visual Studio 2018(版本16.1.X)上可行,但在版本16.3.1上无法编译。我认为这是编译器中的错误,但现在我不确定了。我找不到任何关于std::nullptr_t支持比较运算符的信息,即使GCCClang似乎也不能达成一致。它是否应该工作?如果否,则有没有办法使其工作?定义std::nullptr_t运算符似乎无效。
inline bool operator<(std::nullptr_t, std::nullptr_t)
{
    return false;
}

由于定义关系运算符只能在类参数中进行。

谢谢。


那个运算符不是意味着nullptr != nullptr吗?那不是很糟糕吗? - François Andrieux
你尝试调用 operator<,但定义了 operator==,这是打字错误吗? - 463035818_is_not_a_number
@François Andrieux:您说得对,但这并不重要,因为它无法编译。 - koscelansky
纯属好奇,你在 std::variant 中使用 std::nullptr_t 的用例是什么? - Acorn
1个回答

7

std::nullptr_t类型没有任何关系运算符定义。它只能进行等于比较(也就是说,nullptr == nullptr是合法的且为true,但是nullptr < nullptr是不合法的)。你可以认为这是一个缺陷,我们可以定义关系运算符,使得nullptr < nullptrfalsenullptr <= nullptrtrue等等。但事实就是这样。

variant<Ts...>使用<需要每个Ts...中的类型都支持<操作,但在您的示例中并非如此,因此a < b是不合法的。这不是编译器或库中的任何错误,而是预期的行为。


唯一使<在这里起作用的方法是提供实际具有<的类型 - 也就是将std::nullptr_t包装在某些其他类型中,该类型实际上是有序的。您是否需要特定的std::nullptr_t?也许具有所有六种比较的std::monostate是更好的选择?


好的,假设这是有意义的,但如何解决呢?因为似乎没有简单的方法可以做到 :(. - koscelansky
我实际上正在尝试表示类似于JSON的东西,因此我有std :: monostate表示未定义,std :: nullptr_t表示空值,double表示数字等。这个方法完美地运作,但是使用新的Visual Studio后,它失效了。因此,我认为添加新类型可以解决这个问题。 - koscelansky
1
如果您只需要一个代表空的哨兵,可以使用任何东西,例如 struct my_null {}; - 463035818_is_not_a_number
@koscelansky 我不会重复使用那些 std 类型来表示你的 JSON 值。std::nullptr_t 表示空指针,但是 JSON 中的 null 并不是真正的指针。同样地,JSON 中的 undefined 也不是 std::monostate(一种用于表示 std::variant 中空值的类型)。 - Acorn
@Acorn:对于JSON来说还好,但我正在尝试表示类似于JSON的东西,但不完全一样,因为它用于C++和C++代码,所以我想为什么不使用语言中可以使用的内容,但现在我看到,对于null我需要一个新类型。 - koscelansky
1
如果你真的想要一个空状态std::optional可能不是最糟糕的选择。在你的情况下,可能需要使用std::optional<std::variant<...>> - Timo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接