函数对象是C++中以参数形式传递函数的一个很好的方法,我们将函数包装成类,并且利用()运算符重载实现。
1 2 3 4 5 6 | typedef class hello {
public :
void operator()( double x) {
cout << x << endl;
}
} hello;
|
这时候hello是一个类,我们可以实例化一个对象hello h;,然后通过h(3.14)的方式来调用这个类的成员函数,如果某个函数需要这个函数作为回调函数,则可以将这个hello类的对象传入即可。
因为这是一个类的定义,因此我们完全可以在其中定义一些包含额外信息的成员和一些构造函数,让这个函数对象可以做更多不同的可定制的任务,最终的行为实际上只是调用了这个()运算符重载函数。这种做法比C++函数指针要容易理解得多,也不容易写错。
而Lambda表达式则是C++中的新语法,实现了许多程序员渴望的部分闭包特性。C++中Lambda表达式可以被视为一种匿名函数,这样,对于一些非常短,而且不太可能被其他地方的复用的小函数,可以通过Lambda表达式提高代码的可读性。
在Lambda表达式中对于变量生命期的控制还是与完全支持闭包的JavaScript非常不同,总而言之,C++对于变量声明期的控制在新标准中完全向前兼容,也就是局部变量一定在退出代码块时被销毁,而不是观察其是否被引用。因此,尽管C++的Lambda表达式中允许引用其代码上下文中的值,但是实际上并不能够保证引用的对象一定没有被销毁。
Lambda表达式对于上下文变量的引用有值传递和引用传递两种方式,实际上,无论是哪种方式,在产生Lambda表达式对象时,这些上下文值就已经从属于Lambda表达式对象了,也就是说,代码运行至定义Lambda表达式处时,通过值传递方式访问的上下文变量值已经被写入Lambda表达式的栈中,而引用方式传递的上下文变量地址被写入Lambda表达式的栈中。因此,调用Lambda表达式时得到的上下文变量值就是定义Lambda表达式时这些变量的值,而引用的上下文变量,如果已经被销毁,则会出现运行时异常。
Lambda表达式的基本语法是:
[上下文变量说明](Lambda表达式参数表) -> 返回类型 { 语句块 }
上下文变量说明部分就是说明对于上下文变量的引用方式,=表示值传递,&表示引用传递,例如,&s就表示s变量采用引用传递,不同的说明项之间用逗号分隔,可以为空,但是方括号不能够省略。第一项可以是单独的一个=或者&,表示,所有上下文变量若无特殊说明一律采用值传递/引用传递,什么都不写默认为值传递。
Lambda表达式和TR1标准对应的function<返回类型 (参数表)>对象是可以互相类型转换的,这样,我们也可以将Lambda表达式作为参数进行传递,也可以作为返回值返回。
下面看一个Lambda表达式各种使用方法的完整例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <iostream>
#include <string>
#include <functional> //这是TR1的头文件,定义了function类模板
using namespace std;
typedef class hello {
public :
void operator()( double x) {
cout << x << endl;
}
} hello;
void callhello(string s, hello func) {
cout << s;
func(3.14);
}
void callhello(string s, const function< void ( double x)>& func) {
cout << s;
func(3.14);
}
void callhello(string s, double d) {
[=] ( double x) {
cout << s << x << endl;
}(d);
}
function< void ( double x)> returnLambda(string s) {
cout << s << endl;
function< void ( double x)> f = ([= ] ( double x) {
cout << s << x << endl;
});
s = "changed" ;
return f;
}
function< void ( double x)> returnLambda2(string& s) {
cout << s << endl;
function< void ( double x)> f = ([&s ] ( double x) {
cout << s << x << endl;
});
s = "changed" ;
return f;
}
int main()
{
hello h;
callhello( "hello:" , h);
callhello( "hello lambda:" , -3.14);
int temp = 6;
callhello( "hello lambda2:" , [&] ( double x) -> void {
cout << x << endl;
cout << temp++ << endl;
});
cout << temp << endl;
function< void ( double x)> f = returnLambda( "lambda string" );
f(3.3);
string lambdastring2 = "lambda string2" ;
f = returnLambda2(lambdastring2);
f(6.6);
system ( "pause" );
}
|