lambda表达式是函数式编程的基础。咱对于函数式编程也没有足够的理解,因此这里不敢胡言乱语,有兴趣的可以自己查找相关资料看下。这里只是介绍C++11中的lambda表达式以及与此相关的闭包(closure)。
同样,这里首先给出参考文档
其次,给出两个例子,可以看出lambda表达式的写法
[](int x, int y) { return x + y; } [](int x, int y) -> int { int z = x + y; return z + x; } //表明返回值类型是int型
也就是说,一个lambda表达式很类似于普通的函数定义的写法,区别在于三点,一是没有函数名(你也可以认为函数名是[]),二是这个函数没有普通函数那样的返回值类型,返回值类型的写法在第2行,即在参数列表与函数定义之间以箭头写明,三是在参数列表之前有一个[] (其实这里还可能有更多的形式,后面会说)
第三,lambda表达式的标准形式是什么?
如下。这里先只是列出,后面会详细解释。
lambda-expression:
lambda-introducer lambda-declarator
opt compound-statement
lambda-introducer:
[ lambda-capture
opt ]
lambda-capture:
capture-default
capture-list
capture-default , capture-list
capture-default:
&
=
capture-list:
capture
capture-list , capture
capture:
identifier
& identifier
this
lambda-declarator:
( parameter-declaration-clause ) attribute-specifier
opt mutable
opt exception-specification
opt trailing-return-type
opt 第四,进一步的分析
上面的标准形式中,最不好理解的可能就是lambda-capture了。其实它对应的就是闭包的概念,而作用是描述外部传入的参数。
wiki上有一个例子,如下
std::vector someList; int total = 0; std::for_each(someList.begin(), someList.end(), [&total](int x) { total += x; }); std::cout << total;
这段代码做的事情是把someList中的所有变量求和。其中定义的lambda函数如下,
[&total](int x) {total += x;}
与前面的例子不同,这里的lambda-introducer是[&total]而不是之前的[]。这么写的作用是,在这个lambda函数中以引用方式使用外部变量total,这样求和结果就可以存放于这个变量中。那么类似的,还可以以传值方式使用外部变量,写成[total]就可以,而且,如果需要用到的外部变量较多,可以有简略的写法。一个完整的列表如下(来自wiki,这里我把他们翻译成我们比较习惯的表述形式)
[] // 没有定义任何变量。使用未定义变量会导致错误。 [x, &y] // x 以传值方式传入(默认),y 以引用方式传入。 [&] // 任何被使用到的外部变量皆隐式地以引用方式加以使用。 [=] // 任何被使用到的外部变量皆隐式地以传值方式加以使用。 [&, x] // x 显示地以传值方式加以使用。其余变量以引用方式加以使用。 [=, &z] // z 显示地以引用方式加以使用。其余变量以传值方式加以使用。
第五,代码练习及验证
接下来,我们自己写一些代码来做一些练习以及验证一些事情。以下代码在visual studio 2010下测试通过。
首先是模仿实例写一些代码。
#include #include #include void ShowVector(std::vector & vecTest) { std::for_each(vecTest.begin(), vecTest.end(), [](int x) { std::cout< <<' '; } ); std::cout<
vecTest(10,1); ShowVector(vecTest); std::for_each(vecTest.begin(), vecTest.end(), [](int& x) { x += 2; } ); ShowVector(vecTest); int iTotal = 0; std::for_each(vecTest.begin(), vecTest.end(), [&iTotal](int x) { iTotal += x; } ); std::cout << std::endl << iTotal << std::endl; iTotal = 0; std::for_each(vecTest.begin(), vecTest.end(), [&](int x) { iTotal += x; } ); std::cout << std::endl << iTotal << std::endl; //iTotal = 0; //std::for_each(vecTest.begin(), vecTest.end(), // [=](int x) // { // iTotal += x; // build error,error C3491: 'iTotal': a by-value capture cannot be modified in a non-mutable lambda // } //); //std::cout << std::endl << iTotal << std::endl; //iTotal = 0; //std::for_each(vecTest.begin(), vecTest.end(), // [iTotal](int x) // { // iTotal += x; // build error, error C3491: 'iTotal': a by-value capture cannot be modified in a non-mutable lambda // } //); //std::cout << std::endl << iTotal << std::endl; iTotal = 0; std::for_each(vecTest.begin(), vecTest.end(), [=, &iTotal](int x) { iTotal += x; } ); std::cout << std::endl << iTotal << std::endl; int iAdd = 1; std::for_each(vecTest.begin(), vecTest.end(), [=](int& x) { x += iAdd; } ); ShowVector(vecTest); std::for_each(vecTest.begin(), vecTest.end(), [iAdd](int& x) { x += iAdd; } ); ShowVector(vecTest); char e = 0; scanf_s("%c", &e, 1); return 0; }
1 1 1 1 1 1 1 1 1 1 3 3 3 3 3 3 3 3 3 3 30 30 30 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5
这里值得注意的是其中的注释掉的代码,这里我们以传值方式使用外部变量,但是在lambda函数内部却试图修改该变量的值,其实这是没什么作用的,而visual studio直接给出报错,检查很仔细,不错。
#include "windows.h" #include #include #include void ModVal(int& iVal) { iVal *= 3; } #define ARRAY_SIZE 10000000 int main() { int m = 0; std::vector vecTest(ARRAY_SIZE,0); std::for_each(vecTest.begin(), vecTest.end(), [&m](int& x) { x = m++; } ); // test1 //std::for_each(vecTest.begin(), vecTest.end(), // [](int& x) // { // x *= 3; // } //); // test2 //for (int i = 0; i < ARRAY_SIZE; i++) //{ // vecTest[i] *= 3; //} // test3 std::for_each(vecTest.begin(), vecTest.end(), ModVal); char e = 0; scanf_s("%c", &e, 1); return 0; }
也就是说,最快的是test3,即不采用lambda表达式,而是直接用函数……多少有点出乎意料。而最慢的是直接用for循环的操作,不过它和用lambda表达式的结果很接近。