В качестве предиката можно передать все, что ведет себя как функция, в 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
) занят.