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

这是 C++标准程式库代码中的代码,为什么不等式被测试为 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;
}
10294 次浏览

因为这意味着对 T 的唯一要求是实现一个 operator==。您可以要求 T 具有 operator!=,但是这里的总体思想是您应该尽可能少地给模板的用户带来负担,而其他模板确实需要 operator==

STL 中的大多数函数只能与 operator<operator==一起工作。这要求用户只实现这两个操作符(有时至少实现其中一个)。例如,std::set使用 operator<(更准确地说是 std::less,它默认调用 operator<)而不是 operator>来管理订单。例子中的 remove模板也是类似的情况-它只使用 operator==而不使用 operator!=,所以不需要定义 operator!=

这是 C++标准程式库移除密码的密码。

错了。这不是 C++标准程式库编码。这是 C++标准程式库 remove功能的 一种可能的内部实现。C + + 标准没有规定实际的代码; 它规定了函数原型和必需的行为。

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

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

因为函数只需要 operator==

当涉及到自定义类型的运算符重载时,这种语言允许你做各种奇怪的事情。您完全可以创建一个具有重载 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!=,那么结果将大不相同。

这里有一些很好的答案,我只是想加一点注意事项。

与所有优秀的图书馆一样,标准图书馆的设计(至少)考虑到两个非常重要的原则:

  1. 尽可能少地将责任推给图书馆的使用者。其中一部分原因是,在使用界面时,给他们最少的工作量。(比如定义尽可能少的运算符)。它的另一部分与不让他们感到惊讶或要求他们检查错误代码有关(因此保持接口的一致性,并在出错时抛出来自 <stdexcept>的异常)。

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

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

    (a > = b)等于! (a < b)

    (a = = b)等于! ((a < b) | | (b < a))

    诸如此类。

    当然,在这一点上,人们可能会问为什么 unordered_map需要 operator==(至少在默认情况下)而不是 operator<。答案是,在哈希表中,我们唯一需要的比较是一个相等的比较。因此,更多的 逻辑上一致(即对库用户来说更有意义)要求它们定义一个相等运算符。要求一个 operator<将是困惑的,因为它不是立即明显的为什么你需要它。

EqualityComparable概念 只有要求定义 operator==

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

最有希望的方法是找到一种方法来确定 可以针对特定类型调用 Operal= = ,然后支持它 只有当它可用时,才会出现异常; 在其他情况下,例外情况是 然而,到目前为止,还没有已知的方法来检测 任意运算符表达式 f = = g 的定义是合适的 已知的解决方案具有以下不良特性:

  • 对于不能访问 Operator = = 的对象,在编译时失败(例如,因为它是私有的)。
  • 如果调用 Operator = = 不明确,则在编译时失败。
  • 如果操作符 = = 声明正确,则显示为正确,即使操作符 = = 可能不会编译。

来自 Boost 常见问题解答: 来源

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

对我个人而言,这是关于 很可靠(面向对象设计) L 部分 Liskov代换原则的: “程序中的对象应该可以替换为其子类型的实例,而不改变该程序的正确性。”.在这种情况下,我可以用布尔逻辑中的 ==布尔反演布尔反演替换操作符 !=