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

2023-11-27

我正在尝试使用 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);} );

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

我想我的总体问题是在哪里可以找到这些东西的语法。使用这个例子,我可以声明一些非常简单的事情,但我希望能够用它做更多的事情。我找到了一些地方解释一元谓词应该做什么和不做什么,但实际上没有解释如何声明一个谓词以及它的含义。我对 C++ 中的算法仍然有些陌生,希望学习如何更有效地使用它们。


您可以将任何行为类似于函数的谓词传递给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}
}

现场演示

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

现场演示

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

现场演示

由于 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}
}

现场演示

标准库中有一些工具可以轻松创建包含状态的函数对象,并使用它向函数提供一些参数(即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); };
}

一般来说,您应该更喜欢 lambda 版本,但有时您仍然会看到std::bind(或其 pre-c++11 boost 对应项boost::bind) 受雇。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 C++ 中为 copy_if 等定义“一元谓词”? 的相关文章

随机推荐