是==和!=相互依赖? 我正在学习C++中的运算符重载,我看到了 = = < /COD>和!代码>只是一些特殊的函数,可以为用户定义的类型进行自定义。不过,我关心的是,为什么需要两个不同的定义?我想如果a==b是真的,那么a!=b自动为假,反之亦然,没有其他可能性,因为根据定义,a!=b是!(a==b)。我无法想象在任何情况下这都是假的。但也许我的想象力有限,或者我对某些事情一无所知

是==和!=相互依赖? 我正在学习C++中的运算符重载,我看到了 = = < /COD>和!代码>只是一些特殊的函数,可以为用户定义的类型进行自定义。不过,我关心的是,为什么需要两个不同的定义?我想如果a==b是真的,那么a!=b自动为假,反之亦然,没有其他可能性,因为根据定义,a!=b是!(a==b)。我无法想象在任何情况下这都是假的。但也许我的想象力有限,或者我对某些事情一无所知,c++,operator-overloading,equality,equality-operator,C++,Operator Overloading,Equality,Equality Operator,我知道我可以用一个定义另一个,但这不是我要问的。我也不是在问通过价值或身份来比较对象之间的区别。或者两个对象是否可以同时相等和不相等(这绝对不是一个选项!这些东西是相互排斥的)。我想问的是: 在任何情况下,问两个物体相等的问题是有意义的,但问它们不相等的问题是没有意义的?(无论是从用户的角度,还是从实施者的角度) 如果没有这样的可能性,那么为什么地球上C++将这两个算子定义为两个不同的函数?< /P> 有没有可能在什么情况下问两个问题 物体是平等的确实有意义,但询问它们是否是平等的 平等没有意义

我知道我可以用一个定义另一个,但这不是我要问的。我也不是在问通过价值或身份来比较对象之间的区别。或者两个对象是否可以同时相等和不相等(这绝对不是一个选项!这些东西是相互排斥的)。我想问的是:

在任何情况下,问两个物体相等的问题是有意义的,但问它们不相等的问题是没有意义的?(无论是从用户的角度,还是从实施者的角度)

如果没有这样的可能性,那么为什么地球上C++将这两个算子定义为两个不同的函数?< /P> 有没有可能在什么情况下问两个问题 物体是平等的确实有意义,但询问它们是否是平等的 平等没有意义?(从用户的角度或 实施者的视角)

这是一种观点。也许没有。但是语言设计者,不是无所不知的,决定不限制那些可能想出有意义的情景的人(至少对他们来说)

[……]为什么需要两个不同的定义

一个要考虑的是,有可能比仅仅使用另一个算子更有效地实现其中一个操作符。

(我这里的例子是垃圾,但重点仍然存在,例如,想想bloom过滤器:如果某个东西不在一个集合中,它们允许快速测试,但如果它在一个集合中,测试可能需要更多的时间。)

根据定义,
a!=b
!(a==b)


作为程序员,你有责任抓住这个机会。也许编写测试是件好事

如果
==
=
运算符实际上并不意味着相等,正如
流运算符并不意味着位移位一样。如果你把符号当作其他概念来看待,它们就不必相互排斥

就相等性而言,如果您的用例保证将对象视为不可比较的对象,那么每个比较都应该返回false(或者如果您的操作符返回non-bool,则返回不可比较的结果类型),这是有意义的。我想不出有哪种情况可以保证这一点,但我认为这是合理的。

您不会希望该语言自动重写
a!=b作为
!(a==b)
a==b
返回除
bool
以外的内容时。有几个原因可以让它这么做


您可能有expression builder对象,其中
a==b
不执行任何比较,也不打算执行任何比较,而只是构建一些表示
a==b
的表达式节点

您可能有延迟求值,其中
a==b
不直接执行任何比较,也不打算直接执行任何比较,而是返回某种类型的
lazy
,可在稍后隐式或显式转换为
bool
,以实际执行比较。可能与expression builder对象结合使用,以允许在计算之前进行完整的表达式优化

您可能有一些自定义的
optional
模板类,其中给定可选变量
t
u
,您希望允许
t==u
,但使其返回
optional

可能还有更多我没有想到的。即使在这些示例中,操作
a==b
a!=b
两者都有意义吗,还是
a!=b
不是一回事!(a==b)
,因此需要单独的定义

enum BoolPlus {
    kFalse = 0,
    kTrue = 1,
    kFileNotFound = -1
}

BoolPlus operator==(File& other);
BoolPlus operator!=(File& other);
我不能证明这个操作符重载是正确的,但是在上面的例子中,不可能定义
操作符=
作为
运算符==
的“对立面”

不过,我关心的是,为什么需要两个不同的定义

您不必同时定义两者。
如果它们相互排斥,您仍然可以通过仅定义
==

如果没有这样的可能性,那么为什么地球上C++将这两个算子定义为两个不同的函数?< /P> 因为你可以重载它们,通过重载它们,你可以给它们一个与原来完全不同的含义


例如,运算符
有一些非常成熟的约定,其中
(a==b)
(a!=b)
都是假的,不一定是相反的。特别是在SQL中,与NULL的任何比较都会产生NULL,而不是true或false


如果可能的话,创建这方面的新示例可能不是一个好主意,因为它太不直观了,但是如果您试图对现有约定进行建模,那么可以选择让您的操作符在该上下文中“正确”地操作

也就是说,如果某些类型可能具有运算符
==
,但不具有
=,反之亦然,何时这样做才有意义

一般来说,不,这没有意义。相等运算符和关系运算符通常是成套的。如果存在平等,那么也存在不平等;少于
#include <iostream>
#include <utility>

struct Foo {
    int n;
};

bool operator==(const Foo& lhs, const Foo& rhs)
{
    return lhs.n == rhs.n;
}

bool operator<(const Foo& lhs, const Foo& rhs)
{
    return lhs.n < rhs.n;
}

int main()
{
    Foo f1 = {1};
    Foo f2 = {2};
    using namespace std::rel_ops;

    //all work as you would expect
    std::cout << "not equal:     : " << (f1 != f2) << '\n';
    std::cout << "greater:       : " << (f1 > f2) << '\n';
    std::cout << "less equal:    : " << (f1 <= f2) << '\n';
    std::cout << "greater equal: : " << (f1 >= f2) << '\n';
}
template<typename RhsT>
ResultBuilder& operator == ( RhsT const& rhs ) {
    return captureExpression<Internal::IsEqualTo>( rhs );
}

template<typename RhsT>
ResultBuilder& operator != ( RhsT const& rhs ) {
    return captureExpression<Internal::IsNotEqualTo>( rhs );
}
if( !(a == b || a != b) ){
    // Stateless
}
$ ghci
GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
λ> :i Eq
class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
        -- Defined in `GHC.Classes'