How to use lower_bound() on set of pairs?

The core issue is that your std::set instance is already sorted, but with the default std::pair operator<. You cannot intuitively use the member function std::set::lower_bound, as this uses the comparison function of its class type. You can't use std::lower_bound with a custom predicate neither, as this assumes a sorted range - but sorted with respect to the given predicate, which is not the case.

But there is a workaround for this specific scenario. Note that for each value of x in the set, the minimal associated value of y is the minimal value of type int. As the comparison operator for std::pair instances does a member-wise comparison, you can combine this to:

#include <set>
#include <limits>

const std::set<std::pair<int,int>> s{
   {42, 0}, {42, 1}, {43, 0}, {43, 1}
};

const auto entry = s.lower_bound({43, std::numeric_limits<int>::min()});

This will always find the first or minimal desired entry in the subset that correspond to the given value for the std::pair::first data member. Only the first value is of significance, as the second one is immediately not less than std::numeric_limits<int>::min(), which is what lower_bound is searching for.

If you need this functionality many times, it might be worth putting it into its own helper function (template), e.g.

template <class T>
auto lower_bound_first(const std::set<std::pair<T, T>>& s, T first)
{
   static constexpr T min = std::numeric_limits<T>::min();

   return s.lower_bound({first, min});
}

which you can invoke as

const auto entry = lower_bound_first(s, 43);

for any underlying value types for which the std::numeric_limits specialization is available.

Tags:

C++