std::upper_bound 和 std::lower_bound 的不同比较签名

different compare signature for std::upper_bound and std::lower_bound

这是 std::lower_boundstd::upper_bound 的示例,请注意传递给它们的比较 lambda 的签名 -

const auto lower_x = std::lower_bound(
          points.begin(), points.end(), rec.min_corner.x,

          [](const RankedPoint &rp, const double x) { return rp.point.x < x; });

const auto upper_x = std::upper_bound(
          points.begin(), points.end(), rec.max_corner.x,

          [](const double x, const RankedPoint &rp) { return x < rp.point.x; });

保持签名完全相反的可能原因是什么?我不知道这一点,当我使用 auto 而不是带有错误签名的明确类型时,gcc 编译了它(clang 没有)。让我沮丧了 10 分钟。

lower_boundupper_bound 的自定义比较器版本是简单使用 < 的概括。 lower_bound 产生第一个不小于 value 的元素,因此发生的检查是 elem < value(或实际上是 !(elem < value))。 upper_bound 产生第一个元素 value,但我们不写 elem > value(这需要 operator>),我们只是将顺序翻转为 value < elem。这保持了 operator< 的唯一要求,但结果是参数的顺序颠倒了。

这概括了从 elem < valuecomp(elem, value)value < elemcomp(value, elem)

最终,在设计时我们可以做出两种选择:我们可以在任何地方使用 same 比较器,但对于某些算法,参数的顺序是相反的。或者,我们可以为每种算法使用 不同的 比较器,具体取决于对特定算法有意义的内容。在任何地方使用相同的比较器有很多优点 - 你只需使用相同的比较器:

std::vector<int> vs = ...;
std::sort(vs.begin(), vs.end(), std::greater<>{});
auto lo = std::lower_bound(vs.begin(), vs.end(), 5, std::greater<>{});
auto hi = std::upper_bound(vs.begin(), vs.end(), 5, std::greater<>{});

到处都是相同的比较器,代码看起来是正确的,而且做的事情也是正确的。如果我们翻转 upper_bound() 传递给它的比较器的参数顺序,我们就必须传入 std::less<>{}。这只会……看起来不对。


您可能会对 Ranges TS 感兴趣,它通过可调用投影解决了这个问题。