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

时间:2017-04-04 17:04:43

标签: c++ c++11 stl c++14 c++-standard-library

以下是std::lower_bound&的示例示例。 std::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分钟的挫折感。

1 个答案:

答案 0 :(得分:4)

自定义比较器版本lower_boundupper_bound是简单使用<的概括。 lower_bound产生的第一个元素不小于value,因此发生的检查是elem < value(或!(elem < value)真的)。 upper_bound产生第一个元素更大而不是value,但我们不是编写elem > value(这需要operator>),而是翻转排序到value < elem。这保持了operator<的唯一要求,但结果是,参数的顺序是相反的。

这从elem < valuecomp(elem, value)value < elem推广到comp(value, elem)

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

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感兴趣,它通过可调用的投影来解决这个问题。