我经常听到很多关于c++中的函子。谁能给我一个概述,他们是什么,在什么情况下他们会有用?
当前回答
函子是一个类似于函数的对象。 基本上,一个定义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)
{ ....}
其他回答
对于像我这样的新手来说:经过一些研究,我弄清楚了jalf发布的代码是做什么的。
函子是一个类或结构对象,可以像函数一样被“调用”。这可以通过重载()操作符实现。()操作符(不确定被调用的对象)可以接受任意数量的参数。其他操作符只能取两个值,即+操作符只能取两个值(在操作符的两边各一个),并返回你重载它的任何值。你可以在()操作符中放入任意数量的参数,这就是它的灵活性。
要创建函子,首先要创建类。然后使用您选择的类型和名称参数创建类的构造函数。在同一语句中,后面跟着一个初始化列表(它使用一个冒号操作符,这也是我第一次接触),它使用前面声明的构造函数形参构造类成员对象。然后()操作符被重载。最后,声明已创建的类或结构的私有对象。
我的代码(我发现jalf的变量名令人困惑)
class myFunctor
{
public:
/* myFunctor is the constructor. parameterVar is the parameter passed to
the constructor. : is the initializer list operator. myObject is the
private member object of the myFunctor class. parameterVar is passed
to the () operator which takes it and adds it to myObject in the
overloaded () operator function. */
myFunctor (int parameterVar) : myObject( parameterVar ) {}
/* the "operator" word is a keyword which indicates this function is an
overloaded operator function. The () following this just tells the
compiler that () is the operator being overloaded. Following that is
the parameter for the overloaded operator. This parameter is actually
the argument "parameterVar" passed by the constructor we just wrote.
The last part of this statement is the overloaded operators body
which adds the parameter passed to the member object. */
int operator() (int myArgument) { return myObject + myArgument; }
private:
int myObject; //Our private member object.
};
如果这是不准确的或完全错误的,请随时纠正我!
早在c++出现之前,“functor”这个名字就已经在范畴理论中传统地使用了。这与c++中函子的概念无关。最好使用name function object,而不是c++中所谓的“functor”。这就是其他编程语言调用类似结构的方式。
用于代替普通函数:
特点:
函数对象可以有状态 函数对象适合OOP(它的行为和其他对象一样)。
缺点:
给程序带来了更多的复杂性。
用于代替函数指针:
特点:
函数对象通常可以内联
缺点:
函数对象不能在运行时与其他函数对象类型交换(至少除非它扩展了一些基类,因此会产生一些开销)
用于代替虚函数:
特点:
函数对象(非虚拟)不需要虚表和运行时调度,因此在大多数情况下更有效
缺点:
函数对象不能在运行时与其他函数对象类型交换(至少除非它扩展了一些基类,因此会产生一些开销)
除了在回调中使用,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)
{ ....}
函子基本上就是一个定义操作符()的类。这让你可以创建“看起来像”函数的对象:
// this is a functor
struct add_x {
add_x(int val) : x(val) {} // Constructor
int operator()(int y) const { return x + y; }
private:
int x;
};
// Now you can use it like this:
add_x add42(42); // create an instance of the functor class
int i = add42(8); // and "call" it
assert(i == 50); // and it added 42 to its argument
std::vector<int> in; // assume this contains a bunch of values)
std::vector<int> out(in.size());
// Pass a functor to std::transform, which calls the functor on every element
// in the input sequence, and stores the result to the output sequence
std::transform(in.begin(), in.end(), out.begin(), add_x(1));
assert(out[i] == in[i] + 1); // for all i
函子有几个优点。其一,与常规函数不同,它们可以包含状态。上面的例子创建了一个函数,无论你给它什么,它都会加上42。但是值42并不是硬编码的,它是在创建函数实例时作为构造函数参数指定的。我可以创建另一个加法器,只需要用不同的值调用构造函数,就可以加27。这使得它们可以很好地定制。
As the last lines show, you often pass functors as arguments to other functions such as std::transform or the other standard library algorithms. You could do the same with a regular function pointer except, as I said above, functors can be "customized" because they contain state, making them more flexible (If I wanted to use a function pointer, I'd have to write a function which added exactly 1 to its argument. The functor is general, and adds whatever you initialized it with), and they are also potentially more efficient. In the above example, the compiler knows exactly which function std::transform should call. It should call add_x::operator(). That means it can inline that function call. And that makes it just as efficient as if I had manually called the function on each value of the vector.
如果我传递的是一个函数指针,编译器不能立即看到它指向哪个函数,所以除非它执行一些相当复杂的全局优化,否则它必须在运行时解除对指针的引用,然后进行调用。
推荐文章
- cplusplus.com给出的错误、误解或坏建议是什么?
- 找出质数最快的算法是什么?
- c++枚举类可以有方法吗?
- 格式化IO函数(*printf / *scanf)中的转换说明符%i和%d之间的区别是什么?
- 将析构函数设为私有有什么用?
- main()中的Return语句vs exit()
- 为什么c#不提供c++风格的'friend'关键字?
- 在函数的签名中添加关键字
- 我如何在Visual Studio中预处理后看到C/ c++源文件?
- 为什么在标准容器中使用std::auto_ptr<>是错误的?
- 用比较double和0
- 保护可执行文件不受逆向工程的影响?
- 在c++中字符串前面的“L”是什么意思?
- 为什么std::map被实现为红黑树?
- 空括号的默认构造函数