1

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

4 回答 4

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您可以在 cppreference.com 上阅读更多信息;它从输入范围中删除元素并将它们复制到输出,除非谓词返回 true。

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

于 2013-03-11T08:46:43.160 回答
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

于 2013-03-11T08:47:29.717 回答
1

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

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

此外,谓词需要用参数调用,

pred(someArg);

在您的情况下,这将是一个std::vector<int>::iterator. 还有,save_if不一样move_if。但更重要的是,根本不清楚您要达到什么目标。

于 2013-03-11T08:42:18.983 回答
1

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

这是一个实现,它表示应该移动move之间的东西:bepred(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));
    }
  }
}

请注意,我插入了 at o.end(),因为Container您想要的可能是vector,并且插入 at 的end()速度vector要快得多。

实际上,您可能希望使用输出迭代器(默认情况下,使用std::back_inserterfrom a Container)并将数据输出到该迭代器。同样,remove_move_if这将是一种更好的删除方式,将元素在b-e范围内随机排列,并返回一个iterator.

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

于 2013-03-11T14:35:58.133 回答