Как определить «унарный предикат» для copy_if и т. Д. В C ++? - PullRequest
0 голосов
/ 21 мая 2018

Я пытаюсь использовать std :: copy_if () и выяснил, как работает синтаксис из http://www.cplusplus.com/reference/algorithm/copy_if/:

auto it = std::copy_if (foo.begin(), foo.end(), bar.begin(), [](int i){return !(i<0);} );

Последний аргумент - это тот, который язапутался.Для чего нужны скобки?Могу ли я использовать функцию, которую я написал где-то еще, в качестве аргумента и как это будет работать?Могу ли я передать другой аргумент функции, если я укажу, какую переменную передать ей?

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

1 Ответ

0 голосов
/ 21 мая 2018

В качестве предиката можно передать все, что ведет себя как функция, в copy_if.Есть несколько общих вещей, которые вы можете использовать:

1) Функции

Функции действительно действуют как функции, поэтому они могут быть переданы как предикат copy_if:

bool is_less_than_zero(int i) { return i < 0; }

int main() {
    std::vector<int> a = {1, 2, -2, -1};
    std::vector<int> b;

    std::copy_if(a.begin(), a.end(), std::back_inserter(b), is_less_than_zero);
    // now b will contain the elements {-2, -1}
}

Live Demo

2) Объекты с перегруженным operator()

Объекты могут перегружать operator(), так что они действуют как функции.Их часто называют «функциональными объектами» или «функторами».Это позволяет вам сохранять состояние, которого нельзя достичь с помощью необработанных функций:

struct IsLessThan {
    IsLessThan(int i) : i_{i} {}
    bool operator()(int i) { return i < i_; }
    int i_;
};

int main() {
    std::vector<int> a = {1, 2, -2, -1};
    std::vector<int> b;

    std::copy_if(a.begin(), a.end(), std::back_inserter(b), IsLessThan(0));
    // now b will contain the elements {-2, -1}
}

Live Demo

3) Lambdas

Лямбды являются концептуально анонимными функциями.На самом деле они просто синтаксический сахар для объектов с перегруженным operator(), но это делает их полезным инструментом для создания простых предикатов с небольшим кодом:

int main() {
    std::vector<int> a = {1, 2, -2, -1};
    std::vector<int> b;

    std::copy_if(a.begin(), a.end(), std::back_inserter(b),
                 [](int i){ return i < 0; });
    // now b will contain the elements {-2, -1}
}

Live Demo

Поскольку лямбды действительно являются объектами с перегруженными operator(), они также могут содержать состояние, которое задается через список захвата лямбды:

int main() {
    std::vector<int> a = {1, 2, -2, -1};
    std::vector<int> b;
    int number_to_compare_to = 0;

    std::copy_if(a.begin(), a.end(), std::back_inserter(b),
                 [number_to_compare_to](int i){ return i < number_to_compare_to; });
    // now b will contain the elements {-2, -1}
}

Live Demo

В стандартной библиотеке есть некоторые средства, позволяющие легко создавать функциональные объекты, содержащие состояние, и использовать его для предоставления некоторых параметров функции (а именно std::bind), но большинство изместа, где они были полезны, теперь проще использовать лямбду.То есть следующий код создает два объекта, которые оба действуют одинаково:

bool first_less_than_second(int i, int j) { return i < j; }

int main() {
    auto bind_less_than_zero = std::bind(first_less_than_second, std::placeholders::_1, 0);
    auto lambda_less_than_zero = [](int i){ return first_less_than_second(i, 0); };
}

В общем, вы должны предпочесть лямбда-версию, но вы все равно иногда будете видеть std::bind (или ее пре-с ++11 усиленный коллега boost::bind) занят.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...