如何将谓词传递给算法

时间:2013-03-11 08:36:29

标签: c++ algorithm templates c++11 predicate

我在使用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;

    }

4 个答案:

答案 0 :(得分:3)

试试这个......

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;

}

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

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

答案 1 :(得分:2)

检查一下,我对你的代码进行了一些修改:

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,否则您应该真正移动项目。

答案 2 :(得分:1)

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

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

此外,需要使用参数

调用谓词
pred(someArg);

在您的情况下将是std::vector<int>::iterator。此外,save_ifmove_if不同。但更重要的是,目前尚不清楚你想要实现的目标。

答案 3 :(得分:1)

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

move b e之间的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() {{}}} {{\ n} {{}}

Container

请注意,我在vector处插入,因为您想要的end()可能是vector,而std::back_inserter的{​​{1}}插入速度要快得多。

实际上,您可能想要使用输出迭代器(默认情况下,使用Container中的remove_move_if)并输出数据。同样,b是一种更好的方法,可以删除e - iterator范围内的元素,并返回begin(c)

最后,基于范围的算法值得写。而不是采用开始/结束迭代器对,取一个已覆盖end(c)struct的单个对象返回开始/结束。如果您正在处理子范围,则可以传入开始/结束范围的迭代器{{1}},并且适当地覆盖begin / end。