[C/C++11语法]_[0基础]_[lamba 表达式介绍]
场景
- lambda 表达式在非常多语言里都有一席之地,由于它的原因,能够在函数里高速定义一个便携的函数,或者在函数參数里直接高速构造和传递.
- 它能够说是匿名函数对象,一般仅仅适用于某个函数内,仅仅做暂时使用.
- 通常是须要在对某个数据暂时特殊处理时使用,比方对某种參数类型进行限定的再次封装和行为约束.
參考
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
说明
- lambda 语法.
图1:
Capture Clause(捕抓条款)组合:
规则1:
[] : 空捕抓条款,表明 lambda body 不訪问闭合范围(enclosing scope)的不论什么变量.
[&] : 以引用的方式訪问闭合范围内的前面已声明变量.
[=] : 以值的方式訪问闭合范围内的前面已声明的变量.
[this] : 訪问类实例的this指针.
规则2
- &,=,this 默认类型不能同一时候声明
- 同样类型的捕抓不能和默认类型同一时候声明,比方[&,&i] // 编译错误
- 不同样类型的非默认类型能够同一时候声明.比方[&i,j]
- 对同一个变量不能捕抓多次或者同一时候以不同捕抓方式声明. [&i,&i] [&i,i]
Parameter List(參数列表)
- 和捕抓列表不一样,lambda能够输入參数,普通情况下參数是为了和 C++ 函数转换才须要.
- 也能够使用 lambda 表达式作为參数.
- 在C++14里, 假设使用的是泛型參数,那么你能够使用 auto 声明.
auto y = [] (auto first, auto second)
{
return first + second;
};
Mutable Specification(Mutable关键字)
- 能够使用mutable来改动捕抓条款里声明的传值变量, 注意仅仅是相当于声明了一个本地的mutable变量作为暂时变量而已,并不会改动enclosing scope 变量范围的值. 看 样例1
Exception Specification(异常规范)
- 能够使用throw()来声明这个lambda 不抛出C++异常. 可是在C++11里这样的使用方式已经被废弃.
Return Type(返回类型)
- vs2010 必须声明返回类型.
- gcc 能够不声明返回类型,可是body 里必须有能推导的 return 表达式类型.
其它
- 參考C++14 lambda Expression 的说明.
lambda 和 C++普通函数的转换.
- 依据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
- lambda 在STL里的使用场景.
- 由于vs2010 并不支持lambda 到 C++ 函数的转换,所以并不能通过编译.
- 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
- 使用了lambda 作为 pthread 的回调函数.
- 多线程下使用 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 表达式介绍]的更多相关文章
- [Zlib]_[0基础]_[使用zlib库压缩文件]
场景: 1. WIndows上没找到系统提供的win32 api来生成zip压缩文件, 有知道的大牛麻烦留个言. 2. zlib比較经常使用,编译也方便,使用它来做压缩吧. MacOSX平台默认支持z ...
- [libcurl]_[0基础]_[使用libcurl下载大文件]
场景: 1. 在Windows编程时, 下载http页面(html,xml)能够使用winhttp库,可是并非非常下载文件,由于会失败. 由此引出了WinINet库,无奈这个库的稳定性比較低,使用样例 ...
- [C++11]_[0基础]_[左值引用声明和右值引用声明]
场景: 在 remove_reference 结构体中能看到右值引用的身影 &&, 那么这里的右值引用究竟有什么用呢? 常常也发现int& 和int&& 这两种 ...
- [C/C++标准库]_[0基础]_[使用fstream合并文本文件]
场景: 1. 就是合并文本文件,而且从第2个文件起不要合并第一行. 2. 多加了一个功能,就是支持2个以上的文件合并. 3. 问题: http://ask.csdn.net/questions/192 ...
- [ATL/WTL]_[0基础]_[CBitmap复制图片-截取图片-平铺图片]
场景: 1.当你须要截取图片部分区域作为某个控件的背景. 2.须要平铺图片到一个大区域让他自己主动放大时. 3.或者须要合并图片时. 代码: CDC sdc; CDC ddc; sdc.CreateC ...
- [C/C++标准库]_[0基础]_[交集和补集]
场景: 1. 计算std::vector A和 std::vector B里的同样的元素, 用于保留不删除. 2. 计算std::vector A和 std::vector B里各自的补集, 用于删除 ...
- [C/C++标准库]_[0基础]_[优先队列priority_queue的使用]
std::priority_queue 场景: 1. 对于一个任务队列,任务的优先级由任务的priority属性指明,这时候就须要优先级越高的先运行.而queue并没有排序功能,这时priority_ ...
- [网络]_[0基础]_[使用putty备份远程数据]
场景: 1. putty是windows上訪问linux服务的免费client之中的一个.用它来ssh到远程server备份数据是常见的做法(在没做好自己主动备份机制前), 通过putty界面尽管也不 ...
- [wxWidgets]_[0基础]_[经常更新进度条程序]
场景: 1. 非常根据程序的进展需要处理业务,以更新进度条,进度条的目的是为了让用户知道业务流程的进度.一个进度条程序更友好,让用户知道在程序执行.不是没有反应. 2. 现在更新见过这两种方法的进展. ...
随机推荐
- Windows蓝屏dump文件查看器(转)
Windbg-分析Windows蓝屏原因利器[转]下载地址先声明下,虽然用windbg诊断蓝屏之前网络上已经有人发过教程了,但就我而言, 学会使用windbg来诊断蓝屏也算是自己的原创吧.以前看一个微 ...
- 关于DSP的GPIO的输入输出设置
DSP 28335 的 GPIO的输入设置: GPIO的输入设置时,除了将此GPIO设置为输入之外,还需要将此GPIO口的电平拉高 //RXD3 GpioCtrlRegs.GPBMUX2.bit.GP ...
- Linux命令-添加新硬盘,分区及挂载[转]
http://www.cnblogs.com/qiyebao/p/4484370.html 转自:http://blog.chinaunix.net/uid-25829053-id-3067619.h ...
- OOW 2015 MYSQL
https://events.rainfocus.com/oow15/catalog/oracle.jsp?search.event=openworldEvent&search.mysql=d ...
- OpenSSL再曝CCS注入漏洞-心伤未愈又成筛子
太戏剧了,昨晚看了佳片有约,还不错,2012版的<完美回顾>,像我这样的人依旧选择用电视或者去影院看电影,在没有中间插播广告的时候,体验憋尿得过程中,总是能突然有非常多的想法,这是用电脑或 ...
- 1)Linux程序设计入门--基础知识
)Linux程序设计入门--基础知识 Linux下C语言编程基础知识 前言: 这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将 会学到以下内容: 源程序编译 Makef ...
- iOS开源项目:UIDevice-with-UniqueIdentifier-for-iOS-5
用于替代系统UDID的方法. https://github.com/gekitz/UIDevice-with-UniqueIdentifier-for-iOS-5 1.使用方法: UILabel *l ...
- apache kafka监控系列-KafkaOffsetMonitor(转)
原文链接:apache kafka监控系列-KafkaOffsetMonitor 概览 最 近kafka server消息服务上线了,基于jmx指标参数也写到zabbix中了,但总觉得缺少点什么东西, ...
- XML 简单介绍
先附上一张XML 大概图:详解见博客内容. 一.定义 XML(EXtensible Markup Language) :可扩展标记语言. 设计的用途:用来描述,存储,传输数据信息. 二.特色 1.单纯 ...
- delegate和event的区别 (zz)
一. delegate C#代理实际上类似于C++中的函数指针,因为C#中不存在指针,所以用代理可以完成一些原来在C++中用函数指针完成的操作,例如传递一个类A的方法m给另一个类B的对象,使得类B的对 ...