博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

c++0x 学习笔记之 lambda

Posted on 2011-05-03 20:33  feng wang  阅读(1672)  评论(7编辑  收藏  举报

tips: 因为在博客园丢失文章太多(大多发生在保存草稿时),搬家到 http://feng.free.lc,本处照旧更新,只是稍慢。

有了 lambda 的支持之后,写一些函数式的代码更加方便了,比如
std::vector<int> vec;
std::for_each( vec.begin(), vec.end(),
               [](int i){ std::cout <<i << "\t"; } );
再比如
std::sort( vec.begin(), vec.end(), [](int i, int j)
           { return std::abs(i) < std::abs(j); } );
其中的
[](int i, int j){return std::abs(i) < std::abs(j);}
就是一个 lambda 对象。这个匿名对象返回的类型是
decltype(std::abs(j)<std::abs(j))
需要特别说明的是,只有当 lambda 对象中有 return expression 时,返回类型才可以忽略,否则就是 void。因此,这个 lambda 对象完全写下来是这样的:
[](int i, int j) -> bool
{ return std::abs(i) < std::abs(j); }

这其中的 [] 称为 lambda 导引符(lambda-introducer),里边可以是空的,也可以有几个变量名称:

[] // 未定义任何参数

[x, &y] // x 以值传入,y 以引用传入

[&] //所有外部参数皆以引用传入

[=] // 所有外部参数皆以值传入

[&, x] // x 以值传入,其余以引用传入

[=, &z] // z 以引用传入,其余以值传入

下边是一个使用外部参数的例子

std::vector<double> arr;
double sum = 0;
std::for_each( arr.begin(), arr.end(),
               [&sum](double d){ sum += std::exp(d); } );
其中 sum 以引用传入,相当于计算

[latex]S = \sum_{i=1}^{i=N} e^{A_i}[/latex]

并将结果存入 sum 中。

当然,上边也可直接抓取所有外部参数的引用做简化,这在参数很多的时候很有用

 

std::for_each( arr.begin(), arr.end(),
               [&](double d) { sum+= std::exp(d); } );
  而 lambda 表达式中的 () 中的子参数(parameter-declaration-clause),在个数为 0 的时候可以忽略掉。 因此下边这一句无聊的代码也可以通过编译
[]{}();
其中 []{} 声明了一个匿名的 lambda 对象,抓取 0 个参数,传入 0 个子参数,不执行任何动作就返回 void 了,也就是
[]()->void{}
而加上后边的 () 表示这个 lambda 对象执行了一次。   如果在一个类中, lambda 需要抓取类的其它对象,这时候需要使用 [this], 比如
int f();
struct s
{
  int i;
  void g()
  {
    [this]{ this->i += f(); }();
  }
};
要注意上边例子中对 i 的操作是通过 this->i 实现的,直接对 i 操作会报错。   其实,c++0x 中引入的 auto 跟 lambda 配合得很好,下边代码可以让 lambda 匿名对象不再匿名了
auto hoo = []{};
使用时直接这样就好
hoo();
跟普通类型一样操控
auto goo = new auto([]{});
 

下方有熊出没


  匿名 lambda 对象作为函数缺省对象时,无论是什么外部参数,无论是显式传入还是隐式传入,都是错误的。比如
void f2()
{
  int i = 1;
  void g1(int = ([i]{ return i; })()); // ill-formed
  void g2(int = ([i]{ return 0; })()); // ill-formed
  void g3(int = ([=]{ return i; })()); // ill-formed
  void g4(int = ([=]{ return 0; })()); // OK
  void g5(int = ([]{ return sizeof(i); })()); // ill_formed
}
除非有 [this], 否则使用一个在 lambda 对象之外声明的,有生存期的变量或者引用是不合法的(use of a variable or reference with automatic storage duration declared outside the lambda-expression is ill-formed.)
void f1(int i)
{
  int const N = 20;
  [=]{
        int const M = 30;
        [=]{
             int x[N][M]; // OK: N and M are not "used"
             x[0][0] = i; // error: i is not declared in the immediately
             }; // enclosing lambda-expression
       };
}