C++ 11中的Lambda表达式

C++ 11中的Lambda表达式用于定义并创建匿名的函数对象, 函数式变成风格也融入到C++中。 Lambda 的函数显得与以前的C++规范下的代码风格有些差别,先看一个简单的例子;

 

int main()
{
  int girls = 3;
  int boys = 4;

  auto totalChild = [](int x, int y)->int { return x + y; };

  return totalChild(girls + boys);    
}

 如上代码,我们定义了一个lambda 函数, 该函数接受两个参数(int x,int y),并返回其值。 直观的说, lambda 函数跟普通函数相比不需要函数名(匿名函数), 取而代之的是一对[]。此外,lambda函数还采用了追踪返回类型的方式生命返回值。

 

lambda 函数的定义如下

[capture] (parameters) mutable ->return_type {statement }

其中:

Capture: 捕捉列表,它总是出现在lambda函数的开始,事实上,[] 是lambda函数引出符。捕捉列表由多个捕捉项组成,并以逗号分开,捕捉列表有如下几种形式:

[var]  表示以值传递方式捕捉变量var

[=]  表示以值传递方式捕捉所有父作用域的便利(包括this)

[&var]  表示以引用的方式捕捉变量var

[&]      表示以引用传递捕捉所有父作用域的变量(包括this)

[this]   表示以值传递方式捕捉当前的this 指针

一些常见组合:

[=, &a, &b] 表示以引用传递a 和b,值传递其他的所有变量。

[&, a, this]   表示也值传递a 和this, 引用传递其他所有变量。

需要注意的是捕捉列表不允许变量重复传递, 下面就是一些典型的重复, 会导致编译时错误

[=,a] 这里= 已经以值传递所有变量,a 是一种重复

[&, &this] 这里& 已经以引用传递所有的变量, 捕捉&this 是一种重复。

 

Parameters

参数列表。 与普通函数的参数列表一致。如果不需要参数传递,则可以省略()。

 

mutable

mutable 修饰符。 默认情况下, lambda 函数总是一个const 函数, mutable 可以取消其常量性。 在使用该修饰符的时候, 参数列表不可为空(即使参数为空)

 

->return_type

返回类型。用于追踪返回类型形式声明函数的返回类型。处于方便,不需要返回值的时候也可以连同->一起省略, 此外,在返回类型明确的情况下, 也可以省略该部分, 让编译器对返回类型进行推断。

{statement}

函数体。 与普通函数一致,不过除了使用参数之外,还可以使用所有捕获的变量

 

 关于lambda 的一些注意事项

使用lambda函数的时候,捕捉列表不同会导致不同的结果。 具体来讲,就是按值传递和按引用传递的方式捕捉列表的效果是不一样的。 对于值传递的捕捉列表, 其传递的值在lambda 函数定义的时候已经决定好了。 而按引用传递,其传递的值则等于lambda函数被调用的值。以下的例子演示这个不同:

#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{    
    auto by_val_lambda = [=] { return j + 1; };
    auto by_ref_lambda = [&] { return j + 1; };

    cout << "by_val_lambda: " << by_val_lambda() << endl;
    cout << "by_ref_lambda: " << by_ref_lambda() << endl;

    j++;
    cout << "by_val_lambda: " << by_val_lambda() << endl;
    cout << "by_ref_lambda: " << by_ref_lambda() << endl;
}

程序输出:

by_val_lambda: 13
by_ref_lambda: 13
by_val_lambda: 13
by_ref_lambda: 14

第一次调用by_val_lambda 和by_ref_lambda 时,其运算结果并没有不同,两者均为 12 + 1 = 13. 但第二次调用by_val_lambda的时候, 其计算的是12 + 1 = 13, 相反地,第二次调用by_ref_lambda时计算的是 13 + 1 = 14. 原因在于by_val_lambda中,j被视为常量,一旦初始化以后就不会改变(可以认为之后的只是一个跟父作用域中j同名的常量)而在by_ref_lambda中, j 仍作为父作用域中的值。

在使用lambda函数的时候,如果需要捕捉到值成为lambda 函数的常量,应该按值传递的方式捕捉,反之, 需要捕捉的值称为lambda 函数运行时的常量,则应该使用引用捕捉。

 

 

 

posted @ 2013-10-08 20:11  Minliang  阅读(346)  评论(0编辑  收藏  举报