How do I define a “unary predicate” for copy_if, etc in C++?

扶醉桌前 提交于 2019-12-22 09:39:58

问题


I'm trying to use std::copy_if() and I figured out somewhat how the syntax works from http://www.cplusplus.com/reference/algorithm/copy_if/ :

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

The last argument is the one that I am confused about. What are the brackets for? Can I use a function I wrote somewhere else as an argument and how would that work? Can I pass another argument to the function if I specify which variable to pass to it?

I guess my overall question is where I could find the syntax for these things. Using this example, I can declare some really simple things, but I'd like to be able to do more with it. I've found a few places that explain what a unary predicate should do and not do, but not actually how to declare one and what that would mean. I'm still somewhat new to the algorithms in c++ and hope to learn how to use them more effectively.


回答1:


You can pass anything that behaves like a function as the predicate to copy_if. There are a few common things you can use:

1) Functions

Functions indeed act like functions, so they can be passed as a predicate to 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) Objects with an overloaded operator()

Objects can overload operator() so that they act like functions. These are often called "function objects" or "functors". This lets you store state, which can't be achieved with raw functions:

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

Lambdas are conceptually anonymous functions. In reality, they're just syntactic sugar for objects with an overloaded operator(), but that makes them a useful tool for creating simple predicates with little code:

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

Since lambdas are really objects with an overloaded operator() they can also contain state, which is given via the lambda's capture list:

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

There are some facilities in the standard library to easily create function objects that contain state and use it to supply some of the parameters to a function (namely std::bind), but most of the places they were useful it's now easier to use a lambda instead. That is, the following code creates two objects that both act exactly the same:

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); };
}

In general you should prefer the lambda version, but you will still sometimes see std::bind (or its pre-c++11 boost counterpart boost::bind) employed.



来源:https://stackoverflow.com/questions/50450373/how-do-i-define-a-unary-predicate-for-copy-if-etc-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!