简体   繁体   English

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

[英]Is there a wrapper for floating point numbers in C++20 that would enable me to default the spaceship operator?

I was watching "Using C++20 three way comparison - Jonathan Müller - Meeting C++ 2019" talk and it mentioned problems with classes that contain floating point members.我正在观看“使用 C++20 三路比较 - Jonathan Müller - Meeting C++ 2019”的演讲,它提到了包含浮点成员的类的问题。

Problem comes from the fact that IEEE 754 comparisons involving NaN(s) are weird and do not provide total ordering.问题来自这样一个事实,即涉及 NaN(s) 的 IEEE 754 比较很奇怪,并且不提供总排序。 Talk gives a way to work around this problems, for example using strong_order or manually ignoring NaN values when implementing <=> (assuming that values are never NaN). Talk 提供了一种解决此问题的方法,例如在实现 <=> 时使用strong_order或手动忽略 NaN 值(假设值从不为 NaN)。

My questions is if there are some library wrappers that would enable me to say that "I promise" that my floats are never NaN or that would do slow but valid comparisons on floats(slower but safer since NaNs are now ordered).我的问题是,是否有一些库包装器可以让我说“我保证”我的浮点数永远不会是 NaN或者可以对浮点数进行缓慢但有效的比较(速度较慢但更安全,因为现在订购了 NaN)。 My goal is to avoid manual implementation of spaceship by making member float spaceship friendly(so I can default spaceship).我的目标是通过使成员浮动飞船友好(这样我可以默认飞船)来避免手动实现飞船。

Using example from the talk:使用谈话中的例子:

// original class
struct Temperature{
    double value;
};

struct TemperatureNoNan{
    std::a_number<double> value; // I promise value will never be NaN
    // Now spaceship defaulting works
};

struct TemperatureStrongO{
    std::s_ordered<double> value; // I want strong ordering(2 diff NaNs are not the same)
    // Now spaceship defaulting works
};

"I promise" that my floats are never NaN “我保证”我的浮点数永远不会是 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;
    }
};

Unfortunately, there's no good way to "lift" a comparison category like this.不幸的是,没有像这样“提升”比较类别的好方法。 And it doesn't optimize very well at the moment.而且目前优化得不是很好。

that would do slow but valid comparisons on floats(slower but safer since NaNs are now ordered)这将对浮点数进行缓慢但有效的比较(较慢但更安全,因为现在订购了 NaN)

This one has specific library support by way of either std::strong_order() or std::weak_order() [cmp.alg] depending on what kind of comparison you want:这个通过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)
    }
};

There's nothing in the standard library for this, but it's trivial to implement:标准库中没有这方面的内容,但实现起来很简单:

template<class T,class O=std::weak_ordering>
struct a_number {
  T t;
  O operator<=>(const a_number &rhs) const {
    return t<rhs.t ? O::less : t==rhs.t ? O::equivalent : O::greater;
  }
};

template<class T>
struct s_ordered {
  T t;
  auto operator<=>(const s_number &rhs) const {
    return std::strong_order(t,rhs.t);
  }
};

…with whatever other conversion operators or other conveniences desired. ...使用任何其他转换运算符或其他所需的便利。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM