zoukankan      html  css  js  c++  java
  • c++11 新特性之lambda表达式

      写过c#之后,觉得c#里的lambda表达式和delegate配合使用,这样的机制用起来非常爽。c++11也有了lambda表达式,形式上有细小的差异。形式如下:

      c#:(input parameters) => {statement;}

      c++:[capture list](parameter list) -> return type {statement;}

      c++lambda表达式共分为4各部分。其中parameter list 和 return type 是可以在特定情况下省略的。

    一、capture list

      capture list的作用是捕获lambda所在函数的局部变量其中捕获的类型可以分为值捕获,引用捕获和隐式捕获。

      值捕获:

    1 void fun()
    2 {
    3     int a = 1; 
    4     auto f = [a] { return a; };
    5     a = 0;
    6     auto r = f(); 
    7     cout << r << endl;
    8 }

      结果是1。 和函数值传递一样,行4 lambda表达式捕获的v1是fun函数中局部变量a的一份拷贝,因此行5改变了a并不影响 lambda表达式内的a。

      引用捕获:

    1 void fun()
    2 {
    3     int a = 1;
    4     auto f = [&a] { return a; };
    5     a = 0;
    6     auto r = f(); 
    7     cout << r << endl;
    8 }

      结果为0,行4 捕获的是a对象本身。但是值得一提的是采用引用捕获要保证lambda表达式工作时,引用的变量还是要存在的。

      隐式捕获:

      隐式捕获的方式,就是capture的列表可以用'='和'&'代替,让编译器隐式的推断你使用的是那个变量,然后这两个字符表示捕获的类型‘=’表示值捕获,'&'是引用捕获。采用隐式捕获的方式上述两段代码的行4可以分别表示为:

      auto f = [=] {return a;}

      auto f = [&] {return a;}

      如果需要,你也可以选择混合使用这几种方式:

      

     1 void fun()
     2 {
     3     int a = 1;
     4     int b = 2;
     5     int c = 3;
     6     auto f = [&,a]{cout << "a = " << a << " b=" << b << " c="  << c;};
     7     a++;
     8     b++;
     9     c++;
    10     f();
    11 }

      输出结果 : a = 1 b=3 c=4

      不难发现 b,c都是采用的引用捕获的方式而a采用的值捕获的方式。隐式捕获是这样工作的:对于['=' or '&',capture list or null ]这样捕获列表 ,parameter 是非必须的,相当于对前一种情况的特化(例如template特化那样)。即,如果前一个位置采用了‘=’,capture list可以选择那些需要引用捕获的局部变量或者为空(但是不可以也是值捕获的局部变量)。‘&’同理。

    二、parameter list

      大体来说parameter list用法和普通的函数类似。c++11标准规定lambda表达式不可以有默认参数,但是我在g++ 4.8 和vs2013分别测试如下代码,g++能通过并且给出期望的结果,vs2013报错说lambda表达式不可以有默认参数。显然g++对c++11进行了扩展,为了代码的可移植性,我们还是应该严格遵守标准。

      具体参考c++11文档:5.1.2.5 节:

      The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose param- eters and return type are described by the lambda-expression’s parameter-declaration-clause and trailing- return-type respectively. This function call operator is declared const (9.3.1) if and only if the lambda- expression’s parameter-declaration-clause is not followed by mutable. It is neither virtual nor declared volatile. Default arguments (8.3.6) shall not be specified in the parameter-declaration-clause of a lambda- declarator. Anyexception-specificationspecifiedonalambda-expressionappliestothecorrespondingfunction call operator. An attribute-specifier-seq in a lambda-declarator appertains to the type of the corresponding function call operator. 

    1 int fun()
    2 {
    3     auto f = [](string s1,string s2){cout << s1 << s2;};
    4     f("hello ","world
    ");
    5     auto f2 = [](string s1,string s2="hahah
    "){cout << s1 << s2;};
    6     f2("eric ");
    7 }

    三、return type

      lambda- declarator 中 返回类型也必须是c++11的尾置返回类型(trailing return type)。并且可以省略,可以交给编译器去推断。(vs2013和g++在lambda体使用了if时皆可以推断出返回类型,当然每个if-else分支返回的类型应该统一,否则需要加上位置返回类型的声明)。

    四、mutable

      在lambda表达式的parameter list 和 return type之间加上关键词 mutable ,表示 捕获的值可以在{}中改变,而默认情况捕获的值是不允许改变的(但是捕获的引用是可以改变的)。或许是为了效率,不加mutable的之前的值捕获,可以少开辟一些内存,只有加上mutable之后才真正的为捕获的值分配内存。

  • 相关阅读:
    flash加载外部swf文件层次问题
    C语言之算法初步(骑士周游世界)
    cocos2dx 画一个有边框的矩形
    C++程序员学习历程
    再诡异的现象背后可能只是一个傻X的低级错误——谈调试心态
    [原创]TimeQuest约束外设之ddio的潜规则
    [原创]三段式状态机的思维陷阱
    [原创]TimeQuest约束外设之诡异的Create Generated Clocks用法
    [原创]换位思考多周期约束
    毫秒必争之如何搞定cache(下)
  • 原文地址:https://www.cnblogs.com/ittinybird/p/4547473.html
Copyright © 2011-2022 走看看