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.
In mathematics, particularly in order theory, an upper bound or majorant of a subset S of some preordered set (K, ≤) is an element of K that is greater than or equal to every element of S. Dually, a lower bound or minorant of S is defined to be an element of K that is less than or equal to every element of S.
C++ set lower_bound() function is used to return an iterator pointing to the key in the set container which is equivalent to val passed in the parameter. If val is not present in the set container, it returns an iterator pointing to the immediate next element which is just greater than val.
lower_bound returns an iterator pointing to the first element in the range [first,last) which has a value not less than 'val'. and if the value is not present in the vector then it returns the end iterator.
lower_bound in C++ The lower_bound() method in C++ is used to return an iterator pointing to the first element in the range [first, last) which has a value not less than val. This means that the function returns an iterator pointing to the next smallest number just greater than or equal to that number.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With