如何在C ++中为copy_if等定义“一元谓词”?

Ave*_*een 3 c++ stl

我正在尝试使用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);} );
Run Code Online (Sandbox Code Playgroud)

最后一个论点是我感到困惑的一个。括号用于什么?我可以使用在其他地方编写的函数作为参数,它如何工作?如果指定要传递给该函数的变量,是否可以将另一个参数传递给该函数?

我想我的总体问题是我在哪里可以找到这些语法。使用此示例,我可以声明一些非常简单的内容,但是我希望能够做更多的事情。我已经找到了一些地方来解释一元谓词应该做什么和不应该做什么,但是实际上却没有解释如何声明一个谓词以及这意味着什么。我对c ++中的算法还是有些陌生,希望能学习如何更有效地使用它们。

Mil*_*nek 7

您可以将任何行为像函数一样的谓词传递给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}
}
Run Code Online (Sandbox Code Playgroud)

现场演示

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}
}
Run Code Online (Sandbox Code Playgroud)

现场演示

3)Lambdas

Lambda在概念上是匿名函数。实际上,它们只是具有重载的对象的语法糖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}
}
Run Code Online (Sandbox Code Playgroud)

现场演示

由于lambda实际上是带有重载的对象,operator()因此它们还可以包含状态,该状态通过lambda的捕获列表给出:

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}
}
Run Code Online (Sandbox Code Playgroud)

现场演示

标准库中有一些功能可以轻松创建包含状态的函数对象,并使用它为函数提供一些参数(即std::bind),但是在大多数有用的地方,现在使用lambda变得更容易。也就是说,以下代码创建两个对象,它们的行为完全相同:

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); };
}
Run Code Online (Sandbox Code Playgroud)

通常,您应该更喜欢lambda版本,但有时仍会看到使用std::bind(或c ++ 11 boost之前的版本boost::bind)。