在C++中定义谓词函数的正确方法

cpp*_*der 22 c++ stl predicate

我正在尝试编写用于STL算法的谓词函数.我看到它们是两种定义谓词的方法:

(1)使用如下简单的功能:

bool isEven(unsigned int i)   
{ return (i%2 == 0); }

std::find_if(itBegin, itEnd, isEven); 
Run Code Online (Sandbox Code Playgroud)

(2)使用operator()函数如下:

class checker {  
public:  
  bool operator()(unsigned int i)  
  { return (i%2 == 0); }  
}; 

std::find_if(itBegin, itEnd, checker); 
Run Code Online (Sandbox Code Playgroud)

我更多地使用第二种类型,因为我通常想创建一个谓词对象,其中包含一些成员并在算法中使用它们.当我在checker中添加相同的isEven函数并将其用作谓词时,我收到一个错误:
3.语法,它给出了错误:

class checker { 
    public: 
       bool isEven(unsigned int i) 
       { return (i%2 == 0); }
}; 

checker c; 
std::find_if(itBegin, itEnd, c.isEven); 
Run Code Online (Sandbox Code Playgroud)

调用c.isEven会在编译期间发出错误,指出对某些函数的未定义引用.有人可以解释为什么3.给出错误?此外,我将不胜感激任何关于谓词和迭代器基础知识的指针.

Sve*_*ven 12

指向成员函数的指针需要调用实例,并且您只传递成员函数指针std::find_if(实际上您的语法不正确,因此它根本不起作用;正确的语法std::find_if(itBegin, itEnd, &checker::isEven)然后仍然没有工作原因我给了).

find_if函数希望能够使用单个参数(要测试的对象)调用该函数,但它实际上需要两个来调用成员函数:实例this指针和要比较的对象.

重载operator()允许您同时传递实例和函数对象,因为它们现在是同一个东西.使用成员函数指针,您必须将两条信息传递给只需要一个的函数.

有一种方法可以使用std::bind(需要<functional>标题):

checker c;
std::find_if(itBegin, itEnd, std::bind(&checker::isEven, &c, std::placeholders::_1));
Run Code Online (Sandbox Code Playgroud)

如果您的编译器不支持std::bind,您也可以使用boost::bind它.虽然仅仅因为超载而没有真正的优势operator().


要进一步详细说明,std::find_if需要一个匹配签名的函数指针bool (*pred)(unsigned int)或行为方式的函数.它实际上不需要是函数指针,因为谓词的类型由模板绑定.任何表现得像a的东西bool (*pred)(unsigned int)都是可以接受的,这就是仿函数的工作原理:可以用一个参数调用它们并返回一个bool.

正如其他人所指出的那样,类型checker::isEvenbool (checker::*pred)(unsigned int)不一样的表现原函数指针,因为它需要的实例checker被叫做.

指向成员函数的指针可以在概念上被认为是带有附加参数的常规函数​​指针,this指针(例如bool (*pred)(checker*, unsigned int)).您实际上可以生成一个可以使用std::mem_fn(&checker::isEven)(也来自<functional>)调用的包装器.这仍然没有帮助你,因为现在你有一个函数对象,必须用两个参数而不是只有一个参数调用,但std::find_if仍然不喜欢.

使用std::bind将指向成员函数的this指针视为将指针作为其第一个参数的函数.传递的参数std::bind指定第一个参数应始终为&c,第二个参数应绑定到新返回的函数对象的第一个参数.此函数对象是一个可以使用一个参数调用的包装器,因此可以与之一起使用std::find_if.

虽然std::bind未指定返回类型,但是std::function<bool(unsigned int)>如果需要显式引用绑定的函数对象而不是像我在我的示例中那样将其直接传递给另一个函数,则可以将其转换为(在此特定情况下).


iam*_*ind 5

我想这是因为类型c.isEven()是,

bool (checker::*)(unsigned int) // member function of class
Run Code Online (Sandbox Code Playgroud)

这可能不是find_if(). std::find_if应该期待函数指针 ( bool (*)(unsigned int)) 或函数对象。

编辑:另一个约束:对象static 必须调用class成员函数指针。在你的情况下,即使你成功传递了成员函数,仍然find_if()不会有任何checker对象的任何信息;所以find_if()为了接受成员函数指针参数而重载是没有意义的。

注意:一般来说c.isEven传递成员函数指针不是正确的方式;它应该被传递为,&checker::isEven