我经常听到很多关于c++中的函子。谁能给我一个概述,他们是什么,在什么情况下他们会有用?


当前回答

小之外。你可以使用boost::function从函数和方法中创建函子,如下所示:

class Foo
{
public:
    void operator () (int i) { printf("Foo %d", i); }
};
void Bar(int i) { printf("Bar %d", i); }
Foo foo;
boost::function<void (int)> f(foo);//wrap functor
f(1);//prints "Foo 1"
boost::function<void (int)> b(&Bar);//wrap normal function
b(1);//prints "Bar 1"

你可以使用boost::bind为这个函子添加状态

boost::function<void ()> f1 = boost::bind(foo, 2);
f1();//no more argument, function argument stored in f1
//and this print "Foo 2" (:
//and normal function
boost::function<void ()> b1 = boost::bind(&Bar, 2);
b1();// print "Bar 2"

最有用的是,使用boost::bind和boost::function,你可以从类方法创建函子函数,实际上这是一个委托:

class SomeClass
{
    std::string state_;
public:
    SomeClass(const char* s) : state_(s) {}

    void method( std::string param )
    {
        std::cout << state_ << param << std::endl;
    }
};
SomeClass *inst = new SomeClass("Hi, i am ");
boost::function< void (std::string) > callback;
callback = boost::bind(&SomeClass::method, inst, _1);//create delegate
//_1 is a placeholder it holds plase for parameter
callback("useless");//prints "Hi, i am useless"

你可以创建函子的列表或向量

std::list< boost::function<void (EventArg e)> > events;
//add some events
....
//call them
std::for_each(
        events.begin(), events.end(), 
        boost::bind( boost::apply<void>(), _1, e));

所有这些东西都有一个问题,编译器错误消息不是人类可读的:)

其他回答

函子也可以用来模拟在函数中定义局部函数。参考这个问题和另一个问题。

但是局部函子不能访问外部的自动变量。lambda (c++ 11)函数是一个更好的解决方案。

早在c++出现之前,“functor”这个名字就已经在范畴理论中传统地使用了。这与c++中函子的概念无关。最好使用name function object,而不是c++中所谓的“functor”。这就是其他编程语言调用类似结构的方式。

用于代替普通函数:

特点:

函数对象可以有状态 函数对象适合OOP(它的行为和其他对象一样)。

缺点:

给程序带来了更多的复杂性。


用于代替函数指针:

特点:

函数对象通常可以内联

缺点:

函数对象不能在运行时与其他函数对象类型交换(至少除非它扩展了一些基类,因此会产生一些开销)


用于代替虚函数:

特点:

函数对象(非虚拟)不需要虚表和运行时调度,因此在大多数情况下更有效

缺点:

函数对象不能在运行时与其他函数对象类型交换(至少除非它扩展了一些基类,因此会产生一些开销)

小之外。你可以使用boost::function从函数和方法中创建函子,如下所示:

class Foo
{
public:
    void operator () (int i) { printf("Foo %d", i); }
};
void Bar(int i) { printf("Bar %d", i); }
Foo foo;
boost::function<void (int)> f(foo);//wrap functor
f(1);//prints "Foo 1"
boost::function<void (int)> b(&Bar);//wrap normal function
b(1);//prints "Bar 1"

你可以使用boost::bind为这个函子添加状态

boost::function<void ()> f1 = boost::bind(foo, 2);
f1();//no more argument, function argument stored in f1
//and this print "Foo 2" (:
//and normal function
boost::function<void ()> b1 = boost::bind(&Bar, 2);
b1();// print "Bar 2"

最有用的是,使用boost::bind和boost::function,你可以从类方法创建函子函数,实际上这是一个委托:

class SomeClass
{
    std::string state_;
public:
    SomeClass(const char* s) : state_(s) {}

    void method( std::string param )
    {
        std::cout << state_ << param << std::endl;
    }
};
SomeClass *inst = new SomeClass("Hi, i am ");
boost::function< void (std::string) > callback;
callback = boost::bind(&SomeClass::method, inst, _1);//create delegate
//_1 is a placeholder it holds plase for parameter
callback("useless");//prints "Hi, i am useless"

你可以创建函子的列表或向量

std::list< boost::function<void (EventArg e)> > events;
//add some events
....
//call them
std::for_each(
        events.begin(), events.end(), 
        boost::bind( boost::apply<void>(), _1, e));

所有这些东西都有一个问题,编译器错误消息不是人类可读的:)

除了在回调中使用,c++函子还可以帮助为矩阵类提供Matlab喜欢的访问样式。这里有一个例子。

函子是一个类似于函数的对象。 基本上,一个定义operator()的类。

class MyFunctor
{
   public:
     int operator()(int x) { return x * 2;}
}

MyFunctor doubler;
int x = doubler(5);

真正的优点是函子可以保存状态。

class Matcher
{
   int target;
   public:
     Matcher(int m) : target(m) {}
     bool operator()(int x) { return x == target;}
}

Matcher Is5(5);

if (Is5(n))    // same as if (n == 5)
{ ....}