c++ - 使用仿函数作为谓词的 C++ STL 程序

标签 c++ generics stl

在下面的 C++ STL 程序中,我定义了一个第 N 个仿函数,如果它在第 n 次被撤销,它返回 true。我将它转换为通用算法 remove_if,我得到了一些奇怪的东西。

代码:

#include <iostream>
#include <list>
#include <algorithm>
#include "print.hpp"

using namespace std;

class Nth{
private:
    int nth,ncount;
public:
    Nth(int n):nth(n),ncount(0){}

    bool operator()(int)
    {
        return ++ncount == nth;
    }
};

int main()
{
    list<int> col;
    for (int i = 1;i <=9 ;++i)
    {
        col.push_back(i);
    }

    PRINT_ELEMENTS(col,"col : ");

    list<int>::iterator pos;
    pos = remove_if(col.begin(),col.end(),
        Nth(3));

    col.erase(pos,col.end());

    PRINT_ELEMENTS(col,"nth removed : ");
}

打印.hpp:

#include <iostream>

template <class T>
inline void PRINT_ELEMENTS (const T& coll, const char* optcstr="")
{
    typename T::const_iterator pos;

    std::cout << optcstr;
    for (pos=coll.begin(); pos!=coll.end(); ++pos) {
        std::cout << *pos << ' ';
    }
    std::cout << std::endl;
}

我在 Microsoft Visual Studio 2008 中运行它并得到结果: enter image description here 它删除了我不想要的元素 3 和 6。我以为只会删除 3。 有人可以为我翻译吗?非常感谢。

最佳答案

来自 C++ 标准库:Nicolai M. Josuttis 的教程和引用

发生这种情况是因为算法的通常实现在算法期间在内部复制谓词:

template <class ForwIter, class Predicate>
   ForwIter std::remove_if(ForwIter beg, ForwIter end,
                           Predicate op)
   {
       beg = find_if(beg, end, op);
       if (beg == end) {
           return beg;
       }
       else {
       ForwIter next = beg;
           return remove_copy_if(++next, end, beg, op);
       }
   }

该算法使用 find_if() 查找应删除的第一个元素。但是,它随后使用传递的谓词 op 的拷贝来处理剩余的元素(如果有的话)。这里再次使用了原来状态的Nth,同时也去掉了剩余元素中的第三个元素,其实就是第六个元素。

此行为不是错误。该标准没有指定算法在内部复制谓词的频率。因此,要获得 C++ 标准库的保证行为,您不应传递其行为取决于复制或调用频率的函数对象。因此,如果您为两个参数调用一元谓词并且两个参数相等,那么谓词应该总是产生相同的结果。也就是说,谓词不应因调用而改变其状态,并且谓词的拷贝应具有与原始状态相同的状态。为确保不能因函数调用而改变谓词的状态,应将 operator() 声明为常量成员函数。

关于c++ - 使用仿函数作为谓词的 C++ STL 程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10267944/

相关文章:

c++ - 从函数应用创建 std::vector

c++ - 为什么我不能删除 vector 的最后一个元素

c# - 如何将 repository<T> 中的泛型 T 转换为接口(interface)以在 LINQ to SQL 过滤器中有条件地访问接口(interface)属性?

c++ - 基类 'class std::vector<...>' 有一个非虚析构函数

c++ - OpenMp 并行

c++ - 在 C++ 中存储派生类的实例

java - 为什么更喜欢间接泛型的导入而不是实际的类?

ios - 具有一个参数/参数的泛型类的泛型类

c++ - 为什么使用 vector 会出现链接器错误?

c++ - clang-tidy:如何抑制 C 头文件中的 C++ 警告?