【问题标题】:how to implement a for_each like function in c++?如何在 C++ 中实现类似 for_each 的函数?
【发布时间】:2015-12-01 10:34:19
【问题描述】:

我需要实现一个for_each 函数,如下所示。我知道std::for_each 可以将fn 应用于每个元素,但我们不能擦除std::for_each 中的元素。我需要扩展这个模板函数,以便fn 中,调用者可以一次访问元素和擦除元素。有没有合适的方法来做到这一点?

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class A
{
public:
    explicit A(){
        mVec.clear();
    }
    ~A(){}
    template<class T> void for_each(T fn)
    {
        for(size_t i = 0; i < mVec.size(); ++i)
        {
            //fn can erase element or just visit element
            fn(mVec[i]);
        }
    }
    vector<int> mVec;
};
int main()
{
    A test;
    for(int i = 0; i < 8; ++i)
    {
        test.mVec.push_back(i);
    }
    test.for_each([&test](int i){
        if (i % 2 == 0)
        {
            cout << i << " deleted" << endl;
            test.mVec.erase(find(test.mVec.begin(), test.mVec.end(), i));
        } 
        else
        {
            cout << i << " parse" << endl;
        }
    });

    system("pause");
    return 0;
}

编辑:在for_each 模板函数中,我们不知道调用者是否会擦除元素。擦除元素是在fn

【问题讨论】:

  • 试试vec.erase(std::remove_if(vec.begin(), vec.end(), [](int i){ return i%2==0;}), vec.end()); ?
  • 使用std::remove_if。另请参阅“remove-erase idiom”。
  • 阅读this,了解如何正确地从向量中删除项目。
  • 这个线程很有趣且相关,关于为什么元素在 foreach 中是不可变的。不要被主题中的升c 所迷惑——它实际上是关于foreach 的设计,并且不管实现语言如何都很有趣。 stackoverflow.com/questions/776430/…

标签: c++ vector stl-algorithm


【解决方案1】:

您能否从函数返回一个bool 值,其中true 表示“擦除元素”?然后你的 for_each 函数就变成了这样。

    size_t i = 0;
    for(size_t j = 0; j < mVec.size(); ++j) {
        if (!fn(mVec[j])) {
            // The element must be kept
            if (i != j)
                mVec[i] = std::move(mVec[j]);
            i++;
        }
    }
    mVec.resize(i);

优点还在于,无论删除多少元素,这始终是 O(n)。

编辑:上面的循环实际上只是std::remove_if(),所以@ChenOT 的建议是最好的。或者

    n = std::remove_if(mVec.begin(), mVec.end(), fn) - mVec.begin();
    mVec.resize(n);

【讨论】:

  • 你把lede埋在这里了,也就是说当你从一个向量中删除单个元素时,这个方法是O(n)而不是O(n^2)。 +1。
  • @JohnZwinck,remove_if 也一样。
  • @PaoloBonzini,谢谢。但这无济于事。当我们使用 remove_if 函数时,我们控制删除操作。如果有人删除 fn 中的元素,运行会崩溃。我想实现一个公共模板功能,调用者可以一次擦除元素或访问fn中的元素。
  • @IceYounger,以通用方式解决您想要的问题是不可能的,否则它会被解决。尝试用 remove_if 重新表述您的问题。
  • @PaoloBonzini,谢谢。也许我们可以让 fn 返回一个布尔值。如果 fn 擦除一个元素,则返回 true,然后迭代器停止自增。如果返回 false,则自动递增。
猜你喜欢
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多