C++11 Lambda 表达式

        在 C++ 11 中,lambda 表达式是一种在调用处或函数参数处,定义匿名函数对象的简便方法。它与普通函数不同的是,lambda必须使用尾置返回来指定返回类型。

 

  1. Capture 子句

        Capture 子句可以访问周边范围内的变量,它指定要捕获的变量以及是通过值还是引用进行捕获。有与号 (&) 前缀的变量通过引用访问,没有该前缀的变量通过值访问。  

        可以使用默认捕获模式来指示如何捕获 lambda 中引用的任何外部变量:[&] 表示通过引用捕获所有引用变量,而 [=] 表示通过值捕获它们。可以使用默认捕获模式,然后为特定变量显式指定相反的模式。

 例如,如果 lambda 体通过访问外部引用变量 total 和 值变量 factor,则以下 capture 子句等效:  

[&total, factor]
[factor, &total]
[&, factor]
[factor, &]
[=, &total]
[&total, =]

        如果 capture 子句不包含任何标识符,则不接受任何外部变量。

        如果 capture 子句使用默认捕获模式并捕获所有引用变量&,则该 capture 字句中不能再包含任何形似&标识符 的形式。

        如果 capture 子句使用默认捕获模式并捕获所有值变量 =,则该 capture 子句不能再包含任何形似 = 标识符  的形式。

        变量 或 this 在 capture 子句中出现的次数最多只能是一次。  以下代码片段给出了一些示例。  

struct S { void f(int i); };

void S::f(int i) {
    [&, i]{};    // OK
    [&, &i]{};   // ERROR: i preceded by & when & is the default
    [=, this]{}; // ERROR: this when = is the default
    [i, i]{};    // ERROR: i repeated
}

        capture 后跟省略号是包扩展,如以下示例中所示:

template<class... Args>
void f(Args... args) {
    auto x = [args...] { return g(args...); };
    x();
}

        要在类方法的正文中使用 lambda 表达式,请将 this 指针传递给 Capture 子句,以提供对封闭类的方法和数据成员的访问权限。 

        引用捕获存在生存期依赖,而值捕获却没有生存期依赖。  当 lambda 以异步方式运行时,这一点尤其重要。如果在异步 lambda 中通过引用捕获值变量,当lambda 运行时该值变量将很可能已经消失,从而导致运行时访问冲突。

        2 . 参数列表(可选)(也称 lambda 声明符)  

        除了捕获变量,lambda 还可接受输入参数。  参数列表(在标准语法中称为 lambda 声明符)是可选的,它在大多数方面类似于函数的参数列表。  

int y = [] (int first, int second)
{
    return first + second;
};

        由于参数列表是可选的,因此如果不传递参数且表达式中不包含关键字mutable 、异常处理和返回值,则可以省略空括号。

      3. 可变规范(可选)

        通常,lambda 的函数调用操作是 const-by-value的,不会生成可变的数据成员,但使用 mutable 关键字可以改变这个情况。使用 mutable 关键字可以在lambda 表达式的主体内修改值变量。  

      4. 异常规范(可选)

        你可以使用 throw() 来定义异常,这表示表达式不会抛出任何异常。  与普通函数一样,如果 lambda 表达式定义了 throw() 异常并在lambda体内抛出异常,那Visual C++ 编译器将生成警告C4297。  

      5. 尾随返回类型(可选)

        lambda 表达式自动推导返回类型,而无需使用 auto 关键字,除非你指定了返回类型。 返回类型必须跟在参数列表的后面,你必须在返回类型前面使用关键字 -> 。

        如果 lambda 体仅包含一个返回语句或其表达式不返回值,则可以省略 lambda 表达式的返回类型部分。  如果 lambda 体包含单个返回语句,编译器将从返回表达式的类型推导返回类型。否则,编译器会将返回类型推导为 void。  下面的代码示例片段说明了这一原则。 

auto x1 = [](int i){ return i; }; // OK: return type is int
auto x2 = []{ return{ 1, 2 }; };  // ERROR: return type is void, deducing 
                                  // return type from braced-init-list is not valid

      6. “lambda 体” 

        lambda 表达式的 lambda 体可包含普通方法或函数的主体可包含的任何内容。

        下面是测试实例:

class CPPTest 
{ 
 private:  
   int m_Data; 
 public:  
   CPPTest () : m_Data(20) {}  
   void LambdaTest()  
   {   
     vector<int> vctTemp;   
     vctTemp.push_back(1);   
     vctTemp.push_back(2);   
 
   // 空的Lambda表达式   
   {    
     [](){}();    []{}();   
   }  

   // 无函数对象参数,输出:1 2   
   {    
     for_each(vctTemp.begin(), vctTemp.end(), [](int v){ cout << v << endl; });   
   }
   
   // 操作符重载函数参数按引用传递,输出:2 3   
   {    
     for_each(vctTemp.begin(), vctTemp.end(), [](int &v){ v++; });    
     for_each(vctTemp.begin(), vctTemp.end(), [](int v){ cout << v << endl; });   
   }

   // 以值方式传递局部变量a,输出:11 13 10   
   {    
     int a = 10;    
     for_each(vctTemp.begin(), vctTemp.end(), [a](int v)mutable{ cout << v+a << endl; a++; });  
     cout << a << endl;   
   }    

   // 以引用方式传递局部变量a,输出:11 13 12   
   {    
     int a = 10;    
     for_each(vctTemp.begin(), vctTemp.end(), [&a](int v){ cout << v+a << endl; a++; });    
     cout << a << endl;  
   } 

   // 以引用方式传递作用域内所有可见的局部变量(包括this),输出:11 13 12   
   {    
     int a = 10;   
     for_each(vctTemp.begin(), vctTemp.end(), [&](int v)mutable{ cout << v+a << endl; a++; });
     cout << a << endl;   
   } 

   // 以值方式传递作用域内所有可见的局部变量(包括this),输出:11 12   
   {    
     int a = 10;    
     for_each(vctTemp.begin(), vctTemp.end(), [=](int v){ cout << v+a << endl; });   
   }    

   // 除b按引用传递外,其他均按值传递,输出:11 12 17   
   {    
     int a = 10;    
     int b = 15;    
     for_each(vctTemp.begin(), vctTemp.end(), [=, &b](int v){ cout << v+a << endl; b++; });    
     cout << b << endl;   
   }

   // 传递this,输出:21 22 
   {  
     for_each(vctTemp.begin(), vctTemp.end(), [this](int v){ cout << v+m_nData << endl; });   
   }    
 }  
};

 

转载于:https://my.oschina.net/shou1156226/blog/780866

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值