C++20 中是否有一个浮点数包装器,可以让我默认飞船运算符?

NoS*_*tAl 5 c++ spaceship-operator c++20

我正在观看“使用 C++20 三路比较 - Jonathan M\xc3\xbcller - Meeting C++ 2019”演讲,其中提到了包含浮点成员的类的问题。

\n\n

问题源于这样一个事实:涉及 NaN 的 IEEE 754 比较很奇怪,并且不提供总排序。\nTalk 提供了一种解决此问题的方法,例如使用Strong_order或在实现 <=> 时手动忽略 NaN 值(假设值永远不是 NaN)。

\n\n

我的问题是,是否有一些库包装器可以让我说“我保证”我的浮点数永远不是 NaN,或者可以对浮点数进行缓慢但有效的比较(更慢但更安全,因为 NaN 现在是有序的)。我的目标是通过使成员漂浮宇宙飞船友好来避免手动实现宇宙飞船(这样我可以默认宇宙飞船)。

\n\n

使用演讲中的例子:

\n\n
// original class\nstruct Temperature{\n    double value;\n};\n\nstruct TemperatureNoNan{\n    std::a_number<double> value; // I promise value will never be NaN\n    // Now spaceship defaulting works\n};\n\nstruct TemperatureStrongO{\n    std::s_ordered<double> value; // I want strong ordering(2 diff NaNs are not the same)\n    // Now spaceship defaulting works\n};\n
Run Code Online (Sandbox Code Playgroud)\n

Bar*_*rry 3

“我保证”我的浮点数永远不会是 NaN

template <std::floating_point T>
struct NeverNaN {
    T val;
    constexpr NeverNaN(T val) : val(val) { }
    constexpr operator T() const { return val; }

    constexpr bool operator==(NeverNaN const&) const = default;

    constexpr std::strong_ordering operator<=>(NeverNaN const& rhs) const {
        auto c = val <=> rhs.val;
        assert(c != std::partial_ordering::unordered);
        return c > 0 ? std::strong_ordering::greater :
                c < 0 ? std::strong_ordering::less :
                std::strong_ordering::equal;
    }
};
Run Code Online (Sandbox Code Playgroud)

不幸的是,没有什么好方法可以“提升”这样的比较类别。而且目前优化还不是很好。

这将对浮点数进行缓慢但有效的比较(较慢但更安全,因为 NaN 现在是有序的)

该库通过std::strong_order()std::weak_order() [cmp.alg]提供特定的库支持,具体取决于您想要哪种比较:

template <std::floating_point T>
struct TotallyOrdered {
    T val;
    constexpr TotallyOrdered(T val) : val(val) { }
    constexpr operator T() const { return val; }

    // depends on whether or not you want == NaN to still be false?
    // might need to be: return (*this <=> rhs) == 0; 
    constexpr bool operator==(TotallyOrdered const&) const = default;

    constexpr auto operator<=>(TotallyOrdered const& rhs) const {
        return std::strong_order(val, rhs.val);
        // ... or std::weak_order(val, rhs.val)
    }
};
Run Code Online (Sandbox Code Playgroud)