Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 980
Abhinav Gauniyal Avatar asked Apr 04 '17 17:04

Abhinav Gauniyal


People also ask

What is the difference between lower bound and upper bound?

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.

What does lower_bound return in C++ if element is not present?

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.

What will the lower_bound () function return if the element you passed as an argument isn't present in the vector VECT?

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.

What does the lower_bound function do in C++?

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.


1 Answers

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.

like image 66
Barry Avatar answered Oct 23 '22 04:10

Barry