为什么在很多C ++标准库代码中,不等式被testing为(!(a == b))?

这是来自C ++标准库remove代码的代码。 为什么不平等testing( if (!(*first == val))而不是if (*first != val)

  template <class ForwardIterator, class T> ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val) { ForwardIterator result = first; while (first!=last) { if (!(*first == val)) { *result = *first; ++result; } ++first; } return result; } 

因为这意味着对T的唯一要求是实现一个operator== 。 你可以要求T有一个operator!=但是这里的一般想法是,你应该尽可能减less模板的用户的负担,其他模板需要operator==

STL中的大部分函数只能和operator<operator== 。 这要求用户只实施这两个操作员(或者至less有一个)。 例如, std::set使用了operator< (更确切地说std::less ,默认调用operator< ),而不是operator>来pipe理sorting。 在你的例子中的remove模板是一个类似的情况 – 它只使用operator==而不是operator!=所以operator!=不需要定义。

这是来自C ++标准库删除代码的代码。

错误。 这不是C ++标准库remove代码。 这是C ++标准库removefunction的一个可能的内部实现 。 C ++标准没有规定实际的代码; 它预示着函数原型和所需的行为。

换句话说:从严格的语言angular度来看,你所看到的代码是不存在的 。 它可能来自你的编译器的标准库实现中的一些头文件。 请注意,C ++标准甚至不需要这些头文件存在。 对于编译器实现者来说,文件只是一个方便的方法来满足像#include <algorithm> (即使std::remove和其他函数可用)这样的行的需求。

为什么不平等testing( if (!(*first == val))而不是if (*first != val)

因为该函数只需要operator==

当涉及到自定义types的运算符重载时,该语言允许您执行各种奇怪的事情。 你可以很好地创build一个类,它有一个重载的operator==但没有重载的operator!= 。 或者更糟糕的是:你可以重载operator!=但是让它完全不相关的东西。

考虑这个例子:

 #include <algorithm> #include <vector> struct Example { int i; Example() : i(0) {} bool operator==(Example const& other) const { return i == other.i; } bool operator!=(Example const& other) const { return i == 5; // weird, but nothing stops you // from doing so } }; int main() { std::vector<Example> v(10); // ... auto it = std::remove(v.begin(), v.end(), Example()); // ... } 

如果std::remove使用了operator!= ,那么结果会非常不同。

这里有一些好的答案。 我只是想添加一点点注意。

像所有优秀的图书馆一样,标准图书馆的devise至less有两个非常重要的原则:

  1. 把最less的责任放在你的图书馆的用户身上。 其中一部分与使用界面时给予他们最less的工作量有关。 (比如定义尽可能less的操作符)。 另一部分是不要惊讶它们,或者要求它们检查错误代码(所以保持接口一致,并在出错时抛出<stdexcept>exception)。

  2. 消除所有的逻辑冗余 。 所有的比较都可以从operator<那里推导出来,那么为什么要求用户定义其他呢? 例如:

    (a> b)相当于(b <a)

    (a> = b)相当于!(a <b)

    (a == b)相当于!((a <b)||(b <a))

    等等。

    当然,在这个笔记中,可能会问为什么unordered_map要求operator== (至less默认)而不是operator< 。 答案是在散列表中,我们唯一需要的比较是平等的。 因此, 逻辑上一致 (即对图书馆用户更有意义)要求他们定义一个相等的操作符。 要求operator<会很混乱,因为它不是很明显,为什么你需要它。

EqualityComparable概念需要定义operator==

因此,任何声称使用满足EqualityComparabletypes的函数都不能依赖operator!=存在该types的对象。 (除非有额外的要求暗示operator!=的存在)。

最有前途的方法是find一个方法来确定operator ==是否可以被调用某个特定的types,然后只有在可用时才支持它; 在其他情况下,将会抛出exception。 然而,到目前为止还没有已知的方法来检测是否适当地定义了任意的运算符expression式f == g。 已知的最佳解决scheme具有以下不良品质:

  • 在运算符==不可访问的对象(例如,因为它是私有的)而在编译时失败。
  • 如果调用operator ==不明确,则在编译时失败。
  • 如果运算符==声明是正确的,即使运算符==不能编译,看起来是正确的。

来自Boost FAQ: 来源

知道需要==实现是一个负担 ,你永远不想通过要求!=实现来创build额外的负担。

对我个人而言,它是关于SOLID (面向对象的devise)L部分 – Liskovreplace原则:“程序中的对象应该可以replace其子types的实例,而不会改变该程序的正确性。 在这种情况下,它是运算符!=我可以用布尔逻辑中的==布尔反转代替。