我正在尝试编写用于STL算法的 predicate 函数。我发现有两种定义 predicate 的方法:
(1)使用如下简单函数:
bool isEven(unsigned int i) { return (i % 2 == 0); }
std::find_if(itBegin, itEnd, isEven);
(2)使用operator()函数,如下所示:
class checker {
public:
bool operator()(unsigned int i) { return (i % 2 == 0); }
};
std::find_if(itBegin, itEnd, checker);
我更喜欢使用第二种类型,因为我通常会创建一个 predicate 对象,其中包含一些成员,并在算法中使用它们。当我在checker中添加相同的isEven函数并将其用作 predicate 时,我得到一个错误:
3.产生错误的语法:
class checker {
public:
bool isEven(unsigned int i)
{ return (i%2 == 0); }
};
checker c;
std::find_if(itBegin, itEnd, c.isEven);
调用c.isEven会在编译过程中出现一个错误,说是对某个函数的引用未定义。有人能解释一下为什么3.会出现错误吗?另外,我希望能有任何指针来阅读 predicate 和迭代器的基础知识。
5条答案
按热度按时间ovfsdjhp1#
指向成员函数的指针需要一个示例来调用,而您只传递了指向
std::find_if
的成员函数指针(实际上您的语法不正确,因此它根本不起作用;正确的语法是std::find_if(itBegin, itEnd, &checker::isEven)
,由于我给出的原因,它仍然不起作用)。find_if
函数期望能够使用单个参数(要测试的对象)来调用函数,但实际上它需要两个参数来调用成员函数:示例this
指针和要比较的对象。重载
operator()
允许你同时传递示例和函数对象,因为它们现在是同一个东西,使用成员函数指针,你必须传递两条信息给一个只需要一条信息的函数。有一种方法可以使用
std::bind
(需要<functional>
头文件)来完成此操作:如果你的编译器不支持
std::bind
,你也可以使用boost::bind
,尽管这样做并不比重载operator()
有什么真实的的优势。更详细地说,
std::find_if
需要一个与签名bool (*pred)(unsigned int)
匹配的函数指针,或者类似的函数指针,但实际上它不需要是函数指针,因为 predicate 的类型由模板绑定,任何类似bool (*pred)(unsigned int)
的函数指针都是可以接受的,这就是函子的作用:可以使用单个参数调用它们并返回bool
。正如其他人所指出的,
checker::isEven
的类型是bool (checker::*pred)(unsigned int)
,它的行为不像原始的函数指针,因为它需要一个checker
的示例来调用。指向成员函数的指针在概念上可以被视为接受附加参数
this
指针的常规函数指针(例如,bool (*pred)(checker*, unsigned int)
)。实际上,您可以使用std::mem_fn(&checker::isEven)
生成一个可以通过这种方式调用的 Package 器(同样来自<functional>
)。这仍然没有帮助,因为现在你有一个函数对象,必须用两个参数而不是只有一个参数来调用,std::find_if
仍然不喜欢这样。使用
std::bind
会将指向成员函数的指针视为以this
指针作为第一个参数的函数。传递给std::bind
的参数指定第一个参数应始终为&c
。并且第二个参数应当绑定到新返回的函数对象的第一个参数。这个函数对象是一个 Package 器,可以用一个参数调用,因此可以与std::find_if
一起使用。尽管
std::bind
的返回类型是未指定的,但是如果需要显式引用绑定函数对象,而不是像我在示例中所做的那样将其直接传递给另一个函数,则可以将其转换为std::function<bool(unsigned int)>
(在本例中)。ht4b089n2#
我想是因为
c.isEven()
的类型是,这可能不是X1 M1 N1 X所期望的。X1 M2 N1 X应当期望函数指针(X1 M3 N1 X)或函数对象。
编辑:另一个约束:非
static
成员函数指针必须由class
对象调用。在您的情况下,即使您成功传递了成员函数,find_if()
仍然不会有任何关于checker
对象的信息;所以重载find_if()
来接受成员函数指针参数是没有意义的。注:一般来说
c.isEven
不是传递成员函数指针的正确方式;它应该作为&checker::isEven
传递。holgip5t3#
checker::isEven
不是函数;它是一个成员函数,而且你不能调用一个非静态的成员函数,除非你引用了一个对象,所以你不能在任何你可以传递函数指针的地方,使用一个成员函数,成员指针有特殊的语法,需要调用的不仅仅是()
。这就是函子使用
operator()
的原因;这使得对象可调用而不必使用成员函数指针。camsedfj4#
我更喜欢functors(函数对象),因为它使你的程序更具可读性,更重要的是,它清楚地表达了你的意图。
这是我最喜欢的例子:
注意:最近几年,我们获得了lambda expression支持。
6rvt4ljy5#
上面的例子要求你使用调用运算符(
operator()
),而在你的例子中你调用了函数isEven
,试着重写如下: