场景

  1. lambda 表达式在非常多语言里都有一席之地,由于它的原因,能够在函数里高速定义一个便携的函数,或者在函数參数里直接高速构造和传递.
  2. 它能够说是匿名函数对象,一般仅仅适用于某个函数内,仅仅做暂时使用.
  3. 通常是须要在对某个数据暂时特殊处理时使用,比方对某种參数类型进行限定的再次封装和行为约束.

參考

1. C# Lambda表达式及其优势
2. Lambda Expressions in C++
3. Exception Specifications (throw) (C++)
4. noexcept (C++)
5. what-is-the-lifetime-of-a-c-lambda-expression

说明

  1. lambda 语法.
    图1:

Capture Clause(捕抓条款)组合:

规则1:

[] : 空捕抓条款,表明 lambda body 不訪问闭合范围(enclosing scope)的不论什么变量.
[&] : 以引用的方式訪问闭合范围内的前面已声明变量.
[=] : 以值的方式訪问闭合范围内的前面已声明的变量.
[this] : 訪问类实例的this指针.

规则2

  • &,=,this 默认类型不能同一时候声明
  • 同样类型的捕抓不能和默认类型同一时候声明,比方[&,&i] // 编译错误
  • 不同样类型的非默认类型能够同一时候声明.比方[&i,j]
  • 对同一个变量不能捕抓多次或者同一时候以不同捕抓方式声明. [&i,&i] [&i,i]

Parameter List(參数列表)

  1. 和捕抓列表不一样,lambda能够输入參数,普通情况下參数是为了和 C++ 函数转换才须要.
  2. 也能够使用 lambda 表达式作为參数.
  3. 在C++14里, 假设使用的是泛型參数,那么你能够使用 auto 声明.
auto y = [] (auto first, auto second)
{
    return first + second;
};

Mutable Specification(Mutable关键字)

  1. 能够使用mutable来改动捕抓条款里声明的传值变量, 注意仅仅是相当于声明了一个本地的mutable变量作为暂时变量而已,并不会改动enclosing scope 变量范围的值. 看 样例1

Exception Specification(异常规范)

  1. 能够使用throw()来声明这个lambda 不抛出C++异常. 可是在C++11里这样的使用方式已经被废弃.

Return Type(返回类型)

  1. vs2010 必须声明返回类型.
  2. gcc 能够不声明返回类型,可是body 里必须有能推导的 return 表达式类型.

其它

  1. 參考C++14 lambda Expression 的说明.

lambda 和 C++普通函数的转换.

  1. 依据C++14 lambda表达式条款6, lambda 能够转换为C++函数, 可是必须满足下面的转化条件,并且仅仅能转换为闭包类型自带的特定类型的函数, 闭包类型自带了一个函数指针?

    .
    The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non-
    explicit const conversion function to pointer to function with C ++ language linkage (7.5) having the same
    parameter and return types as the closure type’s function call operator.

– 转换前的 lambda 条件:
1. 非泛型.
2. 没有捕抓列表(即没有捕抓不论什么变量)

– 转换后的 函数
1. 同參数.
2. 同样返回类型.
3. 非虚拟
4. 非显式常量.(non-explicit const)

样例

样例1

  1. lambda 在STL里的使用场景.
  2. 由于vs2010 并不支持lambda 到 C++ 函数的转换,所以并不能通过编译.
  3. mutable 的作用.

vs2010

#include "stdafx.h"
#include <memory>
#include <Windows.h>
#include <stdlib.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <regex>class B
{
public:B(int value):two("B"){one = value;std::cout << "B" << std::endl;}~B(){two.clear(); std::cout << "~B" << std::endl;}int one;std::string two;
};void TestSort()
{std::cout << "TestSort" << std::endl;// 2010也不支持高速枚举. for(B* b: bs)// 创建10个对象std::vector<B*> bs(10);int value = 0;std::generate(bs.begin(),bs.end(),[&value]()->B*{B* b = new B(++value);return b;});// 搜索奇数的对象std::vector<B*> bs2;std::for_each(bs.begin(),bs.end(),[&bs2](B* b){if(b->one % 2){bs2.push_back(b);}});// 排序之前是升序.std::cout << "Before Sort ==" << std::endl;std::for_each(bs2.begin(),bs2.end(),[](B* b){std::cout << b->one << std::endl;});// 降序排列std::cout << "After Sort ==" << std::endl;std::sort(bs2.begin(),bs2.end(),[](B* first,B* second){return first->one > second->one;});std::for_each(bs2.begin(),bs2.end(),[](B* b){std::cout << b->one << std::endl;});
}typedef void (*FUNC)();
void Foo(FUNC func)
{func();
}void TestLambdaAsync()
{std::cout << "TestLambdaAsync ==" << std::endl;//2010 不支持lambda转换为FUNC,它仅仅能用于template里的实现;须要vs2012以上才支持.vs2010支持lambda到FUNC的转换.//     这样就能够直接在 CreateThread里使用 lambda.//g++ 4.8.1 能够.// Foo([](){std::cout << "lambda" << std::endl;});// 错误   2   error C2664: “Foo”: 不能将參数 1 从“`anonymous-namespace'::<lambda6>”转换为“FUNC”
}void TestMutable()
{std::cout << "TestMutable==========" << std::endl;int m = 0;int n = 0;//去掉mutable会出现编译错误.Error:表达式必须是能够改动的左值.// mutable 作用之中的一个就是省略掉本地变量的定义.// [&, n] (int a){ int n1 = n; m = ++n1 + a; }(4);[&, n] (int a)mutable{m = ++n + a; }(4);std::cout << m << std::endl << n << std::endl;
}class Base
{
public:virtual ~Base() {}virtual int call( float ) =0;
};template< typename T>
class Eraser : public Base
{
public:Eraser( T t ) : m_t(t) { }int call( float f ) { return m_t(f); }
private:T m_t;
};class Erased
{
public:template<typename T>Erased( T t ) : m_erased( new Eraser<T>(t) ) { }int do_call( float f ){return m_erased->call( f );}
private:Base* m_erased;
};template<typename FUNC>
class A1
{
public:A1(FUNC func):func_(func){}void Run(){func_();}FUNC func_;
private:
};Erased* GetErased()
{int i = 9;Erased *e_useful = new Erased( [i]( float f ) mutable ->int{ std::cout << ++i << std::endl;return 42; } );return e_useful;
}int main(int argc, char const *argv[])
{TestSort();TestMutable();int i = 0;auto func1 = [i]()mutable{std::cout << "A: " << ++i << std::endl;};A1<decltype(func1)> a(func1);a.Run();Erased* e_useful = GetErased();e_useful->do_call(9);return 0;
}

输出:

TestSort
B
B
B
B
B
B
B
B
B
B
Before Sort ==
1
3
5
7
9
After Sort ==
9
7
5
3
1
TestMutable==========
5
0
A: 1
10

样例2

  1. 使用了lambda 作为 pthread 的回调函数.
  2. 多线程下使用 shared_ptr 的方法.

gcc 4.8.1

// function_lambda_expression.cpp
// compile with: /EHsc /W4
#include <Windows.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <string.h>
#include "pthread.h"class A
{
public:A(){std::cout << "A" << std::endl;buf_ = (char*)malloc(6);strcpy(buf_,"hello");}~A(){free(buf_);buf_ = NULL;std::cout << "~A" << std::endl;}char* buf_;/* data */
};// g++ 4.8.1 支持lambda函数到普通函数的转换,可是有条件,不支持capture(推理)
// 查看C++14规范第6条款关于lambda表达式和普通C++函数的转换关系.
// 传递共享指针,多线程共享变量样例.
void TestLambdaAsync(std::shared_ptr<A>& a1)
{std::cout << "Begin a1.use_count: " << a1.use_count() << std::endl;pthread_t t1;std::shared_ptr<A>* a = new std::shared_ptr<A>(a1);std::cout << "After a1.use_count: " << a1.use_count() << std::endl;// 假设是C函数指针作为參数,那么lambda也不能捕抓不论什么变量,如[&a],不然会报错.// error: cannot convert 'TestLambdaAsync()::__lambda0' to 'void* (*)(void*)' for argument '3' to 'int pthread_create(pthread_t*, pthread_attr_t_* const*, void* (*)(void*), void*)'},NULL);pthread_create(&t1,NULL,[](void* data)->void*{std::shared_ptr<A>* a = reinterpret_cast<std::shared_ptr<A>*>(data);std::cout << "pthread_create: " << (*a)->buf_ << std::endl;delete a;return NULL;},a);
}int main()
{std::cout << "Start ==" << std::endl;std::shared_ptr<A> a(new A());for (int i = 0; i < 10; ++i){TestLambdaAsync(a);}while(a.use_count() > 1){std::cout << "Sleep" << std::endl;Sleep(1);}std::cout << "Exit ==" << std::endl;
}

输出:

Start ==
A
Begin a1.use_count: 1
After a1.use_count: 2
Begin a1.use_count: 2
After a1.use_count: 3
Begin a1.use_count: 3
After a1.use_count: 4
pthread_create: hello
Begin a1.use_count: 3
After a1.use_count: 4
pthread_create: hello
pthread_create: hello
Begin a1.use_count: 2
After a1.use_count: 3
pthread_create: hello
Begin a1.use_count: 3
After a1.use_count: 3
Begin a1.use_count: 3
After a1.use_count: 4
pthread_create: hello
Begin a1.use_count: 3
After a1.use_count: 4
pthread_create: hello
Begin a1.use_count: 3
After a1.use_count: 4
pthread_create: hello
pthread_create: hello
Begin a1.use_count: 2
After a1.use_count: 3
pthread_create: hello
Sleep
pthread_create: hello
Exit ==
~A

[C/C++11语法]_[0基础]_[lamba 表达式介绍]相关推荐

  1. [wxWidgets]_[0基础]_[不常见但有用的类wxStandardPaths]

    场景: 1.wxStandardPaths   用来获取各种系统路径.能够用于存放app的配置数据.比方文档文件夹,appData等. 代码: #include "wx/wxprec.h&q ...

  2. [Windows]_[0基础]_[Release程序的崩溃报告minidump解决方式]

    场景: 1. Release的程序崩溃时,崩溃报告能够让开发者查明代码哪里出了问题,用处大大的. 2. 仅仅实用VS的编译器才支持,所以MinGW就无缘了. 3. 使用了未处理异常过滤处理函数. 4. ...

  3. [C/C++标准库]_[0基础]_[怎样实现std::string自己的Format(sprintf)函数]

    场景: 1.  C语言有自己的sprintf函数,可是这个函数有个缺点,就是不知道须要创建多大的buffer, 这时候能够使用snprintf函数来计算大小,仅仅要參数 buffer为NULL, co ...

  4. [C/C++标准库]_[0基础]_[优先队列priority_queue的使用]

    std::priority_queue 场景: 1. 对于一个任务队列,任务的优先级由任务的priority属性指明,这时候就须要优先级越高的先运行.而queue并没有排序功能,这时priority_ ...

  5. [C/C++]_[0基础]_[static_cast,reinterpret_cast,dynimic_cast的使用场景和差别]

    场景: 1. C++的对象差别于C的原因是他们能够有继承关系, 方法有重载, 覆盖关系等, 他们的对象内存数据结构因此也比較复杂. 2. 非常多情况下我们须要一个父类来存储子类的指针对象进行通用方法的 ...

  6. [Windows]_[0基础]_[使用命令行工具dumpbin分析文件]

    dumpbin(vs拥有) 1. 出口lib函数符号文件(symbols) dumpbin /exports zlib1.lib Microsoft (R) COFF/PE Dumper Versio ...

  7. java ognl表达式_[JavaWeb基础] 029.OGNL表达式介绍

    1.OGNL概述 OGNL,全称为Object-Graph Navigation Language,它是一个功能强大的表达式语言,用来获取和设置Java对象的属性,它旨在提供一个更高的更抽象的层次来对 ...

  8. 华南理工计算机基础知识题,华南理工_计算机应用基础_随堂练习答案(2017年)

    华南理工_计算机应用基础_随堂练习答案(2017年) (18页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 19.9 积分 . . . .华南理工-计算 ...

  9. python解释器环境中用于表示上一次运算结果的特殊变量_知到智慧树_中国画基础_作业题库答案...

    知到智慧树_中国画基础_作业题库答案 更多相关问题 消费者在举行婚礼时穿正式礼服,而在酒吧穿休闲套装,这是因为()情境不同. (内毒素)的主要成分是 ()一般由革兰氏阴性菌产生,是细胞壁中的成份.只有 ...

  10. 深度学习_TensorFlow2.0基础_张量创建,运算,维度变换,采样

    Tensorflow2.0 基础 一:TensorFlow特性 1.TensorFlow An end-to-end open source machine learning platform end ...

最新文章

  1. 2018年摩拜校招嵌入式工程师笔试卷
  2. dnn中个性化服务的使用
  3. 【APICloud系列|30】苹果MAC电脑取消辅助功能-语音识别
  4. Windows环境下搭建Tomcat
  5. Atitit.通过null 参数 反射  动态反推方法调用
  6. 去除lcd图片的摩尔纹_送上妊娠纹的最强攻略!几十款热门产品大测评!
  7. oracle erp 用户手册,oracleerp用户手册-mrp
  8. 三大邮箱品牌:网易,腾讯,阿里说明
  9. 电脑Windows磁盘修复工具如何使用
  10. Vim编辑器快速上手
  11. 标准库函数begin和end的使用
  12. python安装 文件或目录损坏_文件或目录损坏且无法读取怎么办?
  13. SQL注入的防范措施
  14. Jena TDB的使用简介
  15. mysql判断产品是否过期_7个方法教你判断打开的产品是否已过期
  16. 关于重启服务器后wordpress打不开问题
  17. rjs 中的一些记下 免的忘 了
  18. window10 win10 查看本机IP
  19. 人造的风景 --- 东部华侨城一日游感想与收获
  20. flutter bloc记录

热门文章

  1. 微信和QQ,终于可以互通了
  2. 10个小技巧:快速用Python进行数据分析
  3. excel处理几十万行数据_Python处理Excel数据
  4. oracle case grouping,ORACLE GROUPING函数的使用
  5. vue点击按钮打开下拉菜单_vue 点击弹出下拉菜单 点击其他页面收回菜单
  6. 用JAVA打出的计算机_如何用Java代码操作计算机文件?
  7. python的迭代器_python迭代器详解
  8. mysql5和8怎么同时安装_WINDOWS服务器同时安装多个版本的MYSQL的方法,MQYSQL5和MQYSQL8的共存。...
  9. bitmap存入mysql,[MySQL] mysql中bitmap的简单运用
  10. USACO翻译:USACO 2013 DEC Silver三题