我想用std::upper_bound查找某个容器中小于或等于提供值的对象的跨度。这使它成为一个很好的简单单行!
问题是我只对与类的特定原始成员进行比较感兴趣。对容器进行排序是没有问题的,但是当我想使用时std::upper_bound,我需要提供一个对象来进行比较才能使函数正常工作。
对于 MCVE,假设我有一群人,我想找到一个迭代器来:
struct Person {
int age;
double height;
Person(int age, double height) : age(age), height(height) { }
};
int main() {
vector<Person> people = {
Person(5, 12.3),
Person(42, 9.6),
Person(38, 18.4),
Person(31, 8.5)
};
auto sorter = [](const Person& a, const Person& b) {
return a.height < b.height;
};
std::sort(people.begin(), people.end(), sorter);
// All I care about is comparing against this number
// Instead... I have to create a whole new struct
//double cutoff = 10.0;
Person cutoff(123, 10.0);
auto it = std::upper_bound(people.begin(), people.end(), cutoff, sorter);
// Do stuff with 'it' here
}
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是我需要实例化整个对象才能使用std::upper_bound,就像我在上面的代码中所做的那样。我无法对“我提供的价值进行比较”。这使得它非常烦人,因为我要比较的对象对于我来说在不做大量工作的情况下不容易突然出现。
是否有任何可行的策略来解决这个问题,从而产生我能找到的最干净、最紧凑的代码?例如,如果我可以这样做(对于 MCVE),那就太好了:
auto cutoffCompare = [](const Person& p, const double height) {
return p.height < height;
};
// Doesn't exist (AFAIK?)
auto it = std::upper_bound(people.begin(), people.end(), cutoff, sorter, cutoffCompare);
Run Code Online (Sandbox Code Playgroud)
由于它位于程序中的一个热点,我比平常更关心性能,因此我无法执行诸如将对象转换为原始类型然后upper_bound在新列表上执行之类的操作。我可以创建一个全新的对象并将其用作虚拟对象,但随后我将添加大量烦人的代码来完成一些非常简单的事情。我是否陷入了实例化对象的困境?或者我必须滚动自己的 upper_bound 吗?
不要求传递给的值std::upper_bound必须与迭代器的类型匹配,如果您提供正确的比较函数,它可以是您想要的任何内容。你已经非常接近你想要的样本了,只需要翻转参数即可。这里的文档表明比较函数将限制值作为第一个参数。
auto cutoffCompare = [](double height, const Person& p) {
return p.height < height;
};
auto it = std::upper_bound(people.begin(), people.end(), 10.0, cutoffCompare);
Run Code Online (Sandbox Code Playgroud)