C++ 避免代码重复的最佳方法定义比较运算符`<<;=>>;=,=,!=`,但考虑到南斯?

C++ 避免代码重复的最佳方法定义比较运算符`<<;=>>;=,=,!=`,但考虑到南斯?,c++,floating-point,operator-overloading,comparison-operators,C++,Floating Point,Operator Overloading,Comparison Operators,我学数学,xy)。在大多数情况下,浮点运算也是如此,但并不总是如此。当x或y为NaN时,xy),因为将NaN与任何东西进行比较总是返回false。但是,xy)在大多数情况下都是正确的 现在,假设我正在编写一个包含浮点值的类,我想为这个类定义比较运算符。为了明确起见,假设我正在编写一个高精度浮点数,它在内部使用一个或多个double值来存储高精度数字。从数学上讲,这个类的x

我学数学,
xy)
。在大多数情况下,浮点运算也是如此,但并不总是如此。当
x
y
为NaN时,
xy)
,因为将
NaN
与任何东西进行比较总是返回
false
。但是,
xy)
在大多数情况下都是正确的

现在,假设我正在编写一个包含浮点值的类,我想为这个类定义比较运算符。为了明确起见,假设我正在编写一个高精度浮点数,它在内部使用一个或多个
double
值来存储高精度数字。从数学上讲,这个类的
x
定义已经定义了所有其他操作符(如果我与比较操作符的常用语义一致的话)。但是,
NaN
s打破了这个数学上的精确性。因此,也许我不得不单独编写这些运算符,只是为了考虑NAN。但是有更好的办法吗?我的问题是:我如何尽可能避免代码重复,并且仍然尊重
NaN
的行为

相关:。boost/operators如何解决此问题


注意:我标记了这个问题
c++
,因为这是我理解的。请用该语言编写示例。

当您定义运算符时,<您需要处理NaN案例。出于排序和比较的目的,如果将NaN视为小于任何非NaN,则可以执行以下操作:

bool operator<(double l, double r) {
    if (isnan(l)) {
        if (isnan(r)) return false; // NaN == NaN
        return true;        // NaN < rational
    }
    return l < r;       // if r is NaN will return false, which is how we've defined it
}
namespace nullable_relational {
    struct tag {};

    template <typename T>
    bool non_null(T const& lhs, T const& rhs) {
        return !is_null(lhs) && !is_null(rhs);
    }

    template <typename T>
    bool operator== (T const& lhs, T const& rhs) {
        return non_null(lhs, rhs) && !(rhs < lhs) && !(lhs < rhs);
    }
    template <typename T>
    bool operator!= (T const& lhs, T const& rhs) {
        return non_null(lhs, rhs) || !(lhs == rhs);
    }

    template <typename T>
    bool operator> (T const& lhs, T const& rhs) {
        return non_null(lhs, rhs) && rhs < lhs;
    }
    template <typename T>
    bool operator<= (T const& lhs, T const& rhs) {
        return non_null(lhs, rhs) && !(rhs < lhs);
    }
    template <typename T>
    bool operator>= (T const& lhs, T const& rhs) {
        return non_null(lhs, rhs) && !(lhs < rhs);
    }
}
#include <cmath>
class foo
    : private nullable_relational::tag {
    double value;
public:
    foo(double value): value(value) {}
    bool is_null() const { return std::isnan(this->value); }
    bool operator< (foo const& other) const { return this->value < other.value; }
};
bool is_null(foo const& value) { return value.is_null(); }

bool操作符就个人而言,我会使用类似的技术,根据
operatorvalue);}定义比较函数
布尔运算符<(foo const&other)const{返回此->值
同一主题的变体可以是一个比较函数的实现,该函数由比较函数参数化,并负责向比较函数适当地提供参数。例如:

namespace compare_relational {
    struct tag {};

    template <typename T>
    bool operator== (T const& lhs, T const& rhs) {
        return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs == rhs; });
    }
    template <typename T>
    bool operator!= (T const& lhs, T const& rhs) {
        return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs != rhs; });
    }

    template <typename T>
    bool operator< (T const& lhs, T const& rhs) {
        return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs < rhs; });
    }
    template <typename T>
    bool operator> (T const& lhs, T const& rhs) {
        return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs > rhs; });
    }
    template <typename T>
    bool operator<= (T const& lhs, T const& rhs) {
        return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs <= rhs; });
    }
    template <typename T>
    bool operator>= (T const& lhs, T const& rhs) {
        return compare(lhs, rhs, [](auto&& lhs, auto&& rhs){ return lhs >= rhs; });
    }
}

class foo
    : private compare_relational::tag {
    double value;
public:
    foo(double value): value(value) {}

    template <typename Compare>
    friend bool compare(foo const& f0, foo const& f1, Compare&& predicate) {
        return predicate(f0.value, f1.value);
    }
};
名称空间比较\u关系{
结构标记{};
模板
布尔运算符==(T常量和lhs、T常量和rhs){
返回比较(lhs,rhs,[](自动和&lhs,自动和&rhs){返回lhs==rhs;});
}
模板
布尔运算符!=(T常量和左侧、T常量和右侧){
返回比较(lhs,rhs,[](自动和&lhs,自动和&rhs){返回lhs!=rhs;});
}
模板
布尔运算符<(T常量和左侧、T常量和右侧){
返回比较(lhs,rhs,[](自动和&lhs,自动和&rhs){返回lhs(T常量和左侧、T常量和右侧){
返回比较(lhs,rhs,[](自动和&lhs,自动和&rhs){返回lhs>rhs;});
}
模板
布尔运算符=rhs;});
}
}
福班
:private compare_relational::tag{
双重价值;
公众:
foo(双值):值(值){}
模板
友元布尔比较(foo常量和f0、foo常量和f1、比较和谓词){
返回谓词(f0.value,f1.value);
}
};

我可以想象有多个这样的操作生成名称空间,以支持针对常见情况的适当选择。另一个选项可以是不同于浮动点的排序,例如,考虑最小值或最大值的空值。由于有些人使用NaN拳击,因此甚至可以根据不同的NaN值提供订单,并将NaN值安排在适当的位置。例如,使用底层位表示提供浮点值的总顺序,该顺序可能适合将对象用作有序容器中的键,尽管顺序可能不同于由
运算符相关:。这个答案为积分类型提供了一个令人满意的解决方案。但是由于NaN,它不适用于浮点。但是
NaN
应该始终为
false
。您希望x>NaN为false还是true?为了保持与的对称性。@1201programalam NaN
op
始终为false。@Mark B我知道是的,它读起来像是op在更大的上下文中使用双精度,需要在这些上下文中处理NaN。所以也许我不清楚OP在问什么。@1201程序我想在我的课堂上重新设定一个惯例,惯例是
NaN
x
总是
false