简体   繁体   中英

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

Here is a sample example for both std::lower_bound & std::upper_bound , notice the signature of Compare lambda being passed to them -

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; });

What is the possible reasoning behind keeping the signature exact opposite of each other? I wasn't aware of this and gcc compiled (clang didn't) it when I used auto instead of definite types with wrong signatures. Costed me 10 minutes of frustration.

The custom comparator versions of lower_bound and upper_bound are generalizations of simply using < . lower_bound yields the first element that is not less than value , so the check that happens is elem < value (or !(elem < value) really). upper_bound yields the first element greater than value , but we instead of writing elem > value (which would require operator> ), we just flip the ordering to value < elem . This maintains the sole requirement of operator< , but as a result, the order of arguments is reversed.

This generalizes from elem < value to comp(elem, value) and value < elem to comp(value, elem) .

Ultimately, there are two choices that we could make when designing this: we could use the same comparator everywhere, but for some algorithms the order of arguments is reversed. Or, we could use different comparators for every algorithm, depending on what makes sense for that particular algorithm. Using the same comparator everywhere has a lot of advantages - you just use the same comparator:

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<>{});

Same comparator everywhere, code looks correct, and does the right thing. If we flipped the order of arguments that upper_bound() passes to its comparator, we'd have to pass in std::less<>{} . Which would just... look wrong.


You'll probably be interested in the Ranges TS , which solves this problem with invokable projections.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM