Любой способ сделать std :: upper_bound для переменной-члена? - PullRequest
1 голос
/ 06 марта 2019

Я хочу использовать 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
}

Проблема, с которой я столкнулся, заключается в том, что мне нужно создать экземпляр всего объекта просто для использования 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);

Из-за того, что я нахожусь в «горячей точке» программы, где мне важнее производительность, я не могу сделать что-то вроде преобразования объектов в примитивный тип и затем выполнить upper_bound в этом новом списке. Я могу создать совершенно новый объект и использовать его как пустышку, но потом я добавлю раздражающее количество кода, чтобы сделать что-то очень простое. Я застрял в создании объекта? Или я должен бросить свой собственный upper_bound?

1 Ответ

4 голосов
/ 06 марта 2019

Нет требования, чтобы значение, переданное в 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...