如何将谓词传递给算法

how to pass a predicate to algorithm

本文关键字:算法 谓词      更新时间:2023-10-16

我有一个问题使用lambda传递谓词,我试图移动与谓词匹配的元素到第二个容器的开始,但它似乎没有工作,所以有什么问题吗?

#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <utility>
#include <algorithm>

using namespace std;
    template <typename iterator, typename Container, typename T>
    void move_if(iterator b, iterator e, Container o, T pred)
    {
        if(pred)
        {
            o.insert(o.begin(),pred);
        }
    }

    int main()
    {
        vector<int>v{1,2,3,4,5,6,7,8,9,10};
        vector<int>v2;
        for (auto i=v.begin(); i !=v.end(); ++i)
            save_if(v.begin(), v.end(), v2, []( vector<int>::iterator i){return (*i>5);});
        return 0;
    }

试试这个…

int main()
{
    std::vector<int> v{1,2,3,4,5,6,7,8,9,10};
    std::vector<int> v2;
    std::vector<int>::const_iterator
        it = std::remove_copy_if(v.begin(), v.end(),
                                 std::back_inserter(v2),
                                 [](int const& i){return i <= 5;});
    v.erase(it, v.end);
    return 0;
}

您可以在cppreference.com上阅读更多关于remove_copy_if的信息;它从输入范围中删除元素,并将它们复制到输出中,除非谓词返回true。

请注意,这是一个STL remove,因此您需要在之后调用erase来缩小输入。此解决方案的语义与您发布的代码略有不同,但更类似于您对所需内容的描述。

看看这个,我对你的代码做了一些修改:

template <typename iterator, typename Container, typename T>
void move_if(iterator a, iterator b, Container &o, T pred)
{
    for (auto i = a; i != b; i++)
    {
        if (pred(*i))
            o.insert(o.begin(), *i);
    }
}
int main()
{
    vector<int>v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    vector<int>v2;
    move_if(v.begin(), v.end(), v2, [](int i) { return !(i > 5); });
}

注意:如注释所述,如果功能与上述代码相同,建议将move_if重命名为copy_if,否则您应该真正移动项目

没有将谓词作为第二个参数的std::vector::insert重载,所以这一行是错误的:

o.insert(o.begin(),pred);

此外,谓词需要带参数

调用。
pred(someArg);

在您的情况下将是std::vector<int>::iterator。另外,save_ifmove_if也不一样。但更重要的是,它根本不清楚你想要达到什么目标。

在c++ 11中,像[](){return true}这样不捕获任何东西的无状态lambda可以隐式地转换为函数指针。当您执行if(pred)时,您将无状态lambda转换为函数指针,检查该指针是否为非空(它是非空的)。这不是你想要做的。

这是move的实现,be之间的东西,pred(x)说应该移动:

template <typename iterator, typename Container, typename T>
void move_if(iterator b, iterator e, Container o, T pred)
{
  for( auto i = b; i != e;++i) {
    if(pred) {
      o.insert(o.end(),std::move(*i));
    }
  }
}

请注意,我插入在o.end(),因为你想要的Container可能是vector,插入在vectorend()要快得多。

实际上,您可能希望使用一个输出迭代器(默认情况下,从Container使用std::back_inserter)并将数据输出到该迭代器。类似地,remove_move_if将是一个更好的删除方式,将元素从be的范围内打乱,并返回一个iterator

最后,基于范围的算法值得编写。不接受begin/end迭代器对,而是接受一个单独的对象,其上的begin(c)end(c)已经被覆盖以返回begin/end。如果您正在处理子范围,则可以传入迭代器struct的开始/结束范围,并适当地覆盖开始/结束范围。