安溪西坪移动联通网上营业厅改套餐月底可以更换套餐吗

C++中的Lambda表达式详解
投稿:junjie
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了C++中的Lambda表达式详解,本文讲解了基本语法、Lambda的使用等内容,需要的朋友可以参考下
我是搞C++的
一直都在提醒自己,我是搞C++的;但是当C++11出来这么长时间了,我却没有跟着队伍走,发现很对不起自己的身份,也还好,发现自己也有段时间没有写C++代码了。今天看到了C++中的Lambda表达式,虽然用过C#的,但是C++的,一直没有用,也不知道怎么用,就可怜的连Lambda语法都看不懂。好了,这里就对C++中的Lambda进行一个简单的总结,就算是对自己的一个交代,我是搞C++的,我是一个C++ programmer。
一段简单的Code
我也不是文艺的人,对于Lambda的历史,以及Lambda与C++的那段渊源,我也不是很熟悉,技术人,讲究拿代码说事。
#include&iostream&
int main()
&&& int a = 1;
&&& int b = 2;
&&& auto func = [=, &b](int c)-&int {return b += a +};
&&& return 0;
当我第一次看到这段代码时,我直接凌乱了,直接看不懂啊。上面这段代码,如果你看懂了,下面的内容就当时复习了;如果看不懂了,就接着和我一起总结吧。
简单来说,Lambda函数也就是一个函数,它的语法定义如下:
[capture](parameters) mutable -&return-type{statement}
1.[capture]:捕捉列表。捕捉列表总是出现在Lambda函数的开始处。实际上,[]是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数。捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;
2.(parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号“()”一起省略;
3.mutable:mutable修饰符。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空);
4.-&return-type:返回类型。用追踪返回类型形式声明函数的返回类型。我们可以在不需要返回值的时候也可以连同符号”-&”一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导;
5.{statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
与普通函数最大的区别是,除了可以使用参数以外,Lambda函数还可以通过捕获列表访问一些上下文中的数据。具体地,捕捉列表描述了上下文中哪些数据可以被Lambda使用,以及使用方式(以值传递的方式或引用传递的方式)。语法上,在“[]”包括起来的是捕捉列表,捕捉列表由多个捕捉项组成,并以逗号分隔。捕捉列表有以下几种形式:
1.[var]表示值传递方式捕捉变量var;
2.[=]表示值传递方式捕捉所有父作用域的变量(包括this);
3.[&var]表示引用传递捕捉变量var;
4.[&]表示引用传递方式捕捉所有父作用域的变量(包括this);
5.[this]表示值传递方式捕捉当前的this指针。
上面提到了一个父作用域,也就是包含Lambda函数的语句块,说通俗点就是包含Lambda的“{}”代码块。上面的捕捉列表还可以进行组合,例如:
1.[=,&a,&b]表示以引用传递的方式捕捉变量a和b,以值传递方式捕捉其它所有变量;
2.[&,a,this]表示以值传递的方式捕捉变量a和this,引用传递方式捕捉其它所有变量。
不过值得注意的是,捕捉列表不允许变量重复传递。下面一些例子就是典型的重复,会导致编译时期的错误。例如:
3.[=,a]这里已经以值传递方式捕捉了所有变量,但是重复捕捉a了,会报错的;
4.[&,&this]这里&已经以引用传递方式捕捉了所有变量,再捕捉this也是一种重复。
Lambda的使用
对于Lambda的使用,说实话,我没有什么多说的,个人理解,在没有Lambda之前的C++ , 我们也是那样好好的使用,并没有对缺少Lambda的C++有什么抱怨,而现在有了Lambda表达式,只是更多的方便了我们去写代码。不知道大家是否记得C++ STL库中的仿函数对象,仿函数想对于普通函数来说,仿函数可以拥有初始化状态,而这些初始化状态是在声明仿函数对象时,通过参数指定的,一般都是保存在仿函数对象的私有变量中;在C++中,对于要求具有状态的函数,我们一般都是使用仿函数来实现,比如以下代码:
#include&iostream&
typedef enum
&&& add = 0,
class Calc
&&& public:
&&&&&&& Calc(int x, int y):m_x(x), m_y(y){}
&&&&&&& int operator()(type i)
&&&&&&&&&&& switch (i)
&&&&&&&&&&& {
&&&&&&&&&&&&&&& case add:
&&&&&&&&&&&&&&&&&&& return m_x + m_y;
&&&&&&&&&&&&&&& case sub:
&&&&&&&&&&&&&&&&&&& return m_x - m_y;
&&&&&&&&&&&&&&& case mul:
&&&&&&&&&&&&&&&&&&& return m_x * m_y;
&&&&&&&&&&&&&&& case divi:
&&&&&&&&&&&&&&&&&&& return m_x / m_y;
&&&&&&&&&&& }
&&& private:
&&&&&&& int m_x;
&&&&&&& int m_y;
int main()
&&& Calc addObj(10, 20);
&&& cout&&addObj(add)&& // 发现C++11中,enum类型的使用也变了,更“强”了&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& return 0;
现在我们有了Lambda这个利器,那是不是可以重写上面的实现呢?看代码:
#include&iostream&
typedef enum
&&& add = 0,
int main()
&&& int a = 10;
&&& int b = 20;
&&& auto func = [=](type i)-&int {
&&&&&&& switch (i)
&&&&&&&&&&& case add:
&&&&&&&&&&&&&&& return a +
&&&&&&&&&&& case sub:
&&&&&&&&&&&&&&& return a -
&&&&&&&&&&& case mul:
&&&&&&&&&&&&&&& return a *
&&&&&&&&&&& case divi:
&&&&&&&&&&&&&&& return a /
&&& cout&&func(add)&&
显而易见的效果,代码简单了,你也少写了一些代码,也去试一试C++中的Lambda表达式吧。
关于Lambda那些奇葩的东西
看以下一段代码:
#include&iostream&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&
int main()&&&&&&&&&&&&&&&&
{&&&&&&&&&&&&&&&&&&&&&&&&&
&&& int j = 10;&&&&&&&&&&&
&&& auto by_val_lambda = [=]{ return j + 1; };
&&& auto by_ref_lambda = [&]{ return j + 1; };
&&& cout&&"by_val_lambda: "&&by_val_lambda()&&
&&& cout&&"by_ref_lambda: "&&by_ref_lambda()&&
&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& ++j;&&&&&&&&&&&&&&&&&&
&&& cout&&"by_val_lambda: "&&by_val_lambda()&&
&&& cout&&"by_ref_lambda: "&&by_ref_lambda()&&
&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& return 0;&&&&&&&&&&&&&
程序输出结果如下:
by_val_lambda: 11
by_ref_lambda: 11
by_val_lambda: 11
by_ref_lambda: 12
你想到了么???那这又是为什么呢?为什么第三个输出不是12呢?
在by_val_lambda中,j被视为一个常量,一旦初始化后不会再改变(可以认为之后只是一个跟父作用域中j同名的常量),而在by_ref_lambda中,j仍然在使用父作用域中的值。所以,在使用Lambda函数的时候,如果需要捕捉的值成为Lambda函数的常量,我们通常会使用按值传递的方式捕捉;相反的,如果需要捕捉的值成成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。
再来一段更晕的代码:
#include&iostream&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
int main()&&&&&&&&&&&&&&&&&&&&&&&&&
{&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& int val = 0;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& // auto const_val_lambda = [=](){ val = 3; }; wrong!!!
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& auto mutable_val_lambda = [=]() mutable{ val = 3; };
&&& mutable_val_lambda();&&&&&&&&&&
&&& cout&&val&& // 0
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& auto const_ref_lambda = [&]() { val = 4; };
&&& const_ref_lambda();&&&&&&&&&&&&
&&& cout&&val&& // 4
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& auto mutable_ref_lambda = [&]() mutable{ val = 5; };
&&& mutable_ref_lambda();&&&&&&&&&&
&&& cout&&val&& // 5
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
&&& return 0;&&&&&
这段代码主要是用来理解Lambda表达式中的mutable关键字的。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。按照规定,一个const的成员函数是不能在函数体内修改非静态成员变量的值。例如上面的Lambda表达式可以看成以下仿函数代码:
class const_val_lambda
&&& const_val_lambda(int v) : val(v) {}
&&& void operator()() const { val = 3; } // 常量成员函数
对于const的成员函数,修改非静态的成员变量,所以就出错了。而对于引用的传递方式,并不会改变引用本身,而只会改变引用的值,因此就不会报错了。都是一些纠结的规则。慢慢理解吧。
对于Lambda这种东西,有的人用的非常爽,而有的人看着都不爽。仁者见仁,智者见智。不管怎么样,作为程序员的你,都要会的。这篇文章就是用来弥补自己对C++ Lambda表达式的认知不足的过错,以免以后在别人的代码中看到了Lambda,还看不懂这种东西,那就丢大人了。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具1728人阅读
C/C++(833)
技术理论(1005)
其它文章(1414)
编程语言(299)
C++的最新正式标准,由C++标准委员会于日公布,并于2011年9月出版。日的国际标准草案(N3376)是最接近于现行标准的草案(编辑上的修正)。此次标准为C++98发布后13年来第一次重大修正。
C++0x
C++的最新正式标准
对C++核心语言的扩充
C++11标准,原名C++0x。为目前C++编程语言的最新正式标准(ISO/IEC )。它将取代第二版标准ISO/IEC (第一版ISO/IEC 公开于1998年,第二版于2003年更新,分别通称C++98以及C++03,两者差异很小)。C++11包含了核心语言的新机能,并且拓展C++标准程序库,并且加入了大部分的C++ Technical Report 1程序库(数学上的特殊函数除外)。C++ 标准委员会计划在2010年8月之前完成对最终委员会草案的投票,以及于召开的标准会议完成国际标准的最终草案。最终于日公布,并于2011年9月出版。日的国际标准草案(N3376)是最接近于现行标准的草案(编辑上的修正)。此次标准为13年第一次重大修正。[1]
ISO将在年发布C++的后续版本。
1.对C++核心语言的扩充
2.核心语言运行期的强化(右值引用和 move 语义;泛化的常数表达式;对POD定义的修正)
3.核心语言建构期表现的加强(外部模板)
4.核心语言使用性的加强(初始化列表;统一的初始化;类型推导[auto关键字];以范围为基础的 for 循环;Lambda函数与表示法;另一种的函数语法;对象构建的改良;显式虚函数重载;空指针;强类型枚举;角括号;显式类型转换;模板的别名;无限制的unions)
5.核心语言能力的提升(变长参数模板;新的字符串字面值;用户自定义的字面值;多任务存储器模型;thread-local的存储期限;使用或禁用对象的默认函数;long long int 类型;静态允许sizeof运算符作用在类型的数据成员上,无需明确的对象;)
6.C++标准程序库的变更(标准库组件的升级;线程支持;多元组类型;散列表;正则表达式;通用智能指针;可扩展的随机数功能;包装引用;多态函数对象包装器;用于元编程的类型属性;用于计算函数对象返回类型的统一方法)
每个标准的发布都需要一段时间的普及。包括技术图书,编译器支持。C++11标准发布后,美国已经更新了大部分著名C++图书,以支持最新的C++11标准,例如:《C++ Primer (Fifth Edition)》、《C++ Primer Plus (Sixth Edition)》、《The C++ Programming Language (4th Edition)》等等。这几本书都已经有了中文翻译版,分别名叫《C++ Primer 中文版(第五版)》、《C++ Primer Plus 中文版(第六版)》、《C++程序设计语言(第四版)》。各大主流编译器产商也逐步添加了对C++11语法的支持,例如VS2012、g++、clang等都在很大程度上支持C++11标准。图为迄今支持情况。
C++ 11 标准废除了旧的 C++ 98 标准中 auto 的意思(自动变量类型),改成了自动类型推导的意思。
在标准C/C++,使用变量必须明确的指出其类型(强类型)。然而随着模板类型的出现以及模版元编程的技巧,指定类型,特别是函数定义明确的指定返回类型,就不容易表示。在这样的情况下,将中间结果存储与变量是一件困难的事情,可能会需要知道特定的元编程程序库的内部情况。
C++11提供了两种方法缓解上述所遇到的困难。首先被有明确初始化的变量可以使用auto关键字。这会依据该初始化式的具体类型产生变量。示例:
otherVariable =5;&
otherVariable 的类是明确定义的。因为5的类型是int,所以编译器按照“int otherVariable =5;”来编译。
someStrangeCallableType = boost::bind(&SomeFunction, _2, _1, someObject);
someStrangeCallableType 的类型是模版函数 boost::bind对特定引数返回的类型,作为编译器语义分析的一部分,这个类型能够简单地被编译器决定,但用户要通过查看来判断类型就不是一件容易的事情。
除此之外,C++11还定义了 decltype 能够被用来在编译器决定一个表达式的类型。举例:
decltype(someInt)
otherIntegerVariable =5;
decltype 和 auto 一起使用会更为有用,因为 auto 变量的类型只有编译器知道。然而 decltype 对于那些大量运用运算符重载和特化的类型的代码的表示也非常有用。
auto 对于减少冗赘的代码也很有用。举例而言,程序员不用写像下面这样:
for(vector&int&::const_iterator
itr = myvec.begin(); itr != myvec.end();++itr)
可以使用auto简化为:
itr = myvec.begin(); itr != myvec.end();++itr)
这项差异随着程序员开始嵌套容器而更为显著,虽然在这种情况下 typedef 是一个减少代码的好方法。
decltype 所表示的类型可以和 auto 推导出来的不同。
std::vector&int&
&&&&decltype(v[0])
&&&&decltype(c)
&&&&decltype((c))
&&&&decltype(0)
&&&&return
在标准C++中,只要在编译单元内遇到被完整定义的模板,编译器都必须将其实例化(instantiate)。这会大大增加编译时间,特别是模板在许多编译单元内使用相同的参数实例化。看起来没有办法告诉C++不要引发模板的实例化。
C++11将会引入外部模板这一概念。C++已经有了强制编译器在特定位置开始实例化的语法:
template class std::vector&MyClass&;
而C++所缺乏的是阻止编译器在某个编译单元内实例化模板的能力。C++11将简单地扩充前文语法如下:
extern template class std::vector&MyClass&;
这样就告诉编译器不要在该编译单元内将该模板实例化。
以范围为基础的for循环
Boost C++ 定义了许多&范围 (range) &的概念。范围表现有如受控制的串行 (list),持有容器中的两点。有序容器是范围概念的超集 (superset),有序容器中的两个迭代器 (iterator) 也能定义一个范围。这些概念以及操作的算法,将被并入 C++11 标准程序库。不过 C++11 将会以语言层次的支持来提供范围概念的效用。
for 语句将允许简单的范围迭代:第一部分定义被用来做范围迭代的变量,就像被声明在一般for循环的变量一样,其作用域仅只于循环的范围。而在&:&之后的第二区块,代表将被迭代的范围。这样一来,就有了能够允许C-style数组被转换成范围概念的概念图。这可以是std::vector,或是其他符合范围概念的对象。[1]
int my_array[5]={1, 2, 3, 4, 5};for(int& x : my_array){ x *=2;}
g++ 4.7
Rvalue references and move semantics
Lambda expressions
static_assert
Range based for loop
Trailing return type in functions
final method keyword
override method keyword
Strongly typed enums
Forward declared enums
extern templates
&& for nested templates
Local and unnamed types as template arguments
Variadic macros
New built-in types
Initializer lists
explicit type conversion operators
Inline namespaces
sizeof on non-static data members without an instance
Changed restrictions on union members
Raw string literals
User defined literals
Encoding support in literals
Arbitrary expressions in template deduction contexts
Defaulted methods
Deleted methods
Non-static data member initializers
Variadic templates
Default template arguments in function templates
Template aliases
Forwarding constructors
Alignment support
Rvalue references for *this
C99 compatibility
Thread local storage
Inheriting constructors
Generalized attributes
通过对比可以发现,Clang在大多数C++11功能实现上处于领先地位,而Visual Studio则稍显落后。当然,这三个编译器都有着不错的子集适用于跨平台开发。( 注:目前GCC4.8.1已完全支持C++11)
你可以使用类型推断、移动语义、右值引用、nullptr,static_assert,range-based参考对比。同时你还可以使用最终和重写关键字来进行友好的控制。此外,你还可以通过Enums(例举)强类型和提前声明,这里有几个改进后的模板包括extern keyword。
遗憾的是,Visual Studio并不支持较多请求的可变参数模板。另一方面,可变参数宏在这三款编译器中只支持C99标准。继承构造函数和广义属性这些特性并不是在任何地方都能获得支持。本地线程存储是是支持情况最好的一部分(通过非关键字标准)。[2]
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6126741次
积分:73874
积分:73874
排名:第16名
原创:71篇
转载:4300篇
评论:844条
声明:早期转载的文章未标明转载敬请原谅,以后将陆续改过来,向原创者致敬!
有问题可留言
痞子龙3D编程
QQ技术交流群:
(6)(10)(6)(19)(17)(17)(8)(5)(8)(14)(13)(3)(44)(42)(46)(40)(123)(114)(128)(159)(168)(40)(45)(43)(38)(5)(6)(7)(2)(3)(7)(24)(5)(5)(16)(17)(16)(66)(7)(55)(2)(37)(16)(1)(10)(6)(37)(5)(31)(18)(31)(128)(333)(203)(256)(59)(78)(57)(16)(39)(10)(27)(16)(8)(26)(32)(53)(56)(45)(142)(228)(6)(10)(6)(9)(6)(9)(22)(25)(18)(83)(208)(442)(111)(32)(1)走进c++0x,体验不一样的c++ - 推酷
走进c++0x,体验不一样的c++
& & & & 好吧,之前我错误的认为c++0x就是添加了一些大多数人不懂的语法,比如bind,lambda,或者是一些使用起来可有可无的特性,比如auto,或者是可以通过具体代码方式来避免的,比如move。
& & & & 不过阅读了漫话c++0x系列文章,我发现c++0x真的是一门新的语言,并且是足够漂亮的新语言。说实话,我们平时写代码确实不会遇到什么复杂的语法(如果自己写了自以为很炫,但是别人都看不懂的语句,就自行面壁去)。c++一些容易产生bug或者是非常难以理解的东西应该是我们尽量去避免的(比如,多继承和模板),模板不是不可以用,而是应该限定到非常有限的地方。
& & & & 但是随着c++0x的普及(各主流编译器都已经支持),学习使用c++新语法就变得非常有必要了。通过下面介绍的一些特性,我们的代码可以变得更加简洁,从而可以使我们的代码更加容易阅读(无论是对他人而言,还是对自己而言)。
=============================分割线=================================
auto用来声明变量
& & & 把这个列在第一位是因为这个是使用最广泛并且最容易被使用的。它最常见的地方就是容器遍历,请看下面的代码:
std::map& std::string, std::vector&int& &
for (std::map& std::string, std::vector&int& &::iterator i = mp.begin(); i != mp.end(); ++i)
/// traverse the map
std::map& std::string, std::vector&int& &
for (auto i = mp.begin(); i != mp.end(); ++i)
/// traverse the map
二、for循环新的遍历方式(像java一样的遍历方式)
std::vector& int&
for (std::vector& int&::iterator i = v.begin(); i != v.end(); ++i)
/// use iterator i to operate the element in v
std::vector& int&
for (int num: v) /// for (auto num: v) is also OK
/// num is the element in v
std::vector& int&
for (int & num: v) /// for (auto & num: v)
is also OK
/// num is the reference of the element in v
统一初始化的语法,
C++0x中,所有的初始化都可以用{}来完成了,达到了真正意义上的统一,语法也十分简洁。这里有一点需要注意,
在C++0x的的统一初始化逻辑中,参数的个数可以少于成员,但不能多于,如果少于的话,没初始化的成员通过缺省的方式初始化
/// c++98中,各种形式的初始化
const int x(5);
///& 直接初始化
const int y = 5;
///& copy构造初始化
int arr[] = {1, 2, 3};
///& 大括号初始化
struct Point{int x,};
const Point p = {1, 2};
///& 大括号初始化
class PointX
PointX(int x, int y);
const PointX px(1, 2);
///& 构造函数初始化
std::vector& int& vec(arr, arr+3); ///& 从别的容器初始化
/// c++98中,不能初始化的情况
Foo() : data(???) {} ///& 不能在这里初始化数组
int data[3];
int * data = new int[3]; ///& 不能在这里初始化堆上内存
/// 与上面c++98中能初始化的例子相对应
int x {1};
int y {2};
int arr[] {x, y, 3};
struct Point {int x,};
Point p {1, 2};
class PointX
PointX(int x, int y);
PointX px {1, 2};
std::vector& int& vec {1, 2, 3};
/// 与上面C++98中不能初始化的例子相对应
Foo() : data {1,2,3} {}
int data[3];
int * data = new int[3] {1, 2, 3};
除了上面介绍这些,还有一些更酷的写法
void Func(const std::vector& int&& v);
Func({1, 2, 3, 4, 5});
Point MakePoint() { return { 0, 0 }; }
四、function & &其实就是boost::function,最常见的用途就是实现函数回调,并且function是可以像对象一样被用作参数或是被保存到容器中,这个是相对大一些的内容,细节请自行google,简单示例如下
#include & functional&
std::function& size_t(const char*)& print_
/// normal function -& std::function object
size_t CPrint(const char*) { ... }
print_func = CP
print_func(&hello world&):
/// functor -& std::function object
class CxxPrint
size_t operator()(const char*) { ... }
print_func =
print_func(&hello world&);
五、bind & &其实就是boost::bind,一般和function配合起来使用,用来替代原来stl中丑陋的bind1st和bind2nd,示例如下
#include & functional&
int Func(int x, int y);
auto bf1 = std::bind(Func, 10, std::placeholders::_1);
bf1(20); ///& same as Func(10, 20)
int Func(int x, int y);
auto bf2 = std::bind(&A::Func, a, std::placeholders::_1, std::placeholders::_2);
bf2(10, 20); ///& same as a.Func(10, 20)
std::function& int(int)& bf3 = std::bind(&A::Func, a, std::placeholders::_1, 100);
bf3(10); ///& same as a.Func(10, 100)
六、lambda & & 一般说到匿名函数或者闭包(
)就是跟这个东西有关了,这个比上面两个东西更加“高级”了些,但是同样的概念在其他语言中是非常常见的基本语法。
无论是python,lua,还是java,objective-c匿名函数都非常常用。 & 示例如下:
vector& int&
/// 1. simple lambda
auto it = std::find_if(vec.begin(), vec.end(), [](int i) { return i & 50; });
bool operator(int i) const { return i & 50; }
auto it = std::find_if(vec.begin(), vec.end(), A());
/// 2. lambda return syntax
std::function& int(int)& square = [](int i) -& int { return i * }
/// 3. lambda expr: capture of local variable
int min_val = 10;
int max_val = 1000;
auto it = std::find_if(vec.begin(), vec.end(), [=](int i) {
return i & min_val && i & max_
auto it = std::find_if(vec.begin(), vec.end(), [&](int i) {
return i & min_val && i & max_
auto it = std::find_if(vec.begin(), vec.end(), [=, &max_value](int i) {
return i & min_val && i & max_
/// 4. lambda expr: capture of class member
void DoSomething();
std::vector&int&
/// 4.1 capture member by this
void A::DoSomething()
auto it = std::find_if(m_vec.begin(), m_vec.end(), [this](int i){
return i & m_min_val && i & m_max_ });
/// 4.2 capture member by default pass-by-value
void A::DoSomething()
auto it = std::find_if(m_vec.begin(), m_vec.end(), [=](int i){
return i & m_min_val && i & m_max_ });
/// 4.3 capture member by default pass-by-reference
void A::DoSomething()
auto it = std::find_if(m_vec.begin(), m_vec.end(), [&](int i){
return i & m_min_val && i & m_max_ });
把上面三点结合起来使用,
C++将会变得非常强大,有点函数式编程的味道了。对于用bind来生成function和用lambda表达式来生成function, 通常情况下两种都是ok的,但是在参数多的时候,bind要传入很多的std::placeholders,而且看着没有lambda表达式直观,所以通常建议优先考虑使用lambda表达式。
七、thread mutex和
condition_variable & 多线程相关内容终于标准化了,多线程的代码也不会再有一大堆#ifdef 来区分不同平台了。 使用起来也很方便(就是boost::thread)
#include & iostream&
#include & string&
#include & thread&
class Printer
void Print(int id, std::string& name)
std::cout & & &id=& && id && &, name=& &&
void Hello()
std::cout && &hello world& && std::
int main()
int id = 1;
std::string name(&xiao5ge&);
std::thread t1(&Printer::Print, p, id, name);
std::thread t2(std::bind(&Printer::Print, p, id, name));
std::thread t3([&]{ p.Print(id, name); });
std::thread t4(Hello);
t4.join();
t3.join();
t2.join();
t1.join();
#include & mutex&
// global vars
int data = 0;
std::mutex data_
// thread 1
std::lock_guard& std::mutex& locker(data_mutex);
// thread 2
std::lock_guard& std::mutex& locker(data_mutex);
condition_variable &条件变量其实就是实现这么一个效果,如果变量不为真,则线程挂起,如果为真,则线程唤醒。
std::atomic& bool& is_finish(false);
std::mutex finish_
std::condition_variable finish_
// thread 1
std::unique& std::mutex& locker(finish_mutex);
// 1. loop wait
while (!is_finish)
finish_cond.wait(locker);
// 2. wait until prediction is true, loop inside
finish_cond.wait(locker, []{ return is_ });
// 3. wait until eithor prediction is true or timeout
finish_cond.wait(locker, std::chrono::seconds(1),
[]{ return is_ });
// thread 2
is_finish =
// 1. notify one of the waiter
finish_cond.notify_one();
// 2. notify all the waiter
finish_cond.notify_all();
关于条件变量的补充:
condition_variable: 用在std::unique_lock& std::mutex&上wait, 比较高效。
condition_variable_any: 可以用在任意mutex上wait, 比较灵活,但效率比condition_variable差一些。
关于wait,有三种基本的用法:第1种是在指定的条件上循环等待,直到条件为真notify时才会继续执行后面的逻辑;第2种用法语义上和第1种是一样的,但是不是用户做显式的loop等待,用户传入一个需要满足的条件的closure, wait一直等到这个条件为真被notify时才会返回继续执行下面的逻辑,可以理解为这时候,在wait内部有一个loop;第3 种用法,加了一个超时的语义,wait一直等到条件为真或者超时,被notify时才会返回继续执行下面的逻辑。
关于notify, 有两种:第1种是notify_one, 只唤醒一个在wait的线程; 第2种是notify_all,唤醒所有在wait的线程,相当于一个broadcast的语义
八、一些小的修改:
“&&”可以做为嵌套模板的闭合端,不需要显式的加空格
std::vector& std::list&int&& vi1;
/// fine in C++0x, error in C++98
std::vector& std::list&int& & vi2; /// fine in C++0x and C++98
新增加空指针类型nullptr。 这个主要是因为NULL的宏定义无法区分是指针还是整型,那么重载或者模板推倒时就会出现错误。其他情况下nullptr与NULL相同。
&unicode的支持,新增加char16_t和char32_t类型
/// char 'x'
/// wchar_t 'x'
/// char16_t 'x', UCS-2
/// char32_t 'x' UCS-4
/// std::basic_string typedefs for all character types:
std::string s1;
/// std::basic_string& char&
std::wstring s2;
/// std::basic_string& wchar_t&
std::u16string s3; /// std::basic_string& char16_t&
std::u32string s4; /// std::basic_string& char32_t&
原字符串的支持(raw string),等同于python中的r“xxxx”,在这个字符串中\r\n这样的转义字符不再被转义。
std::string noNewlines(&(\\n\\n)&);
std::string cmd(&(ls /home/docs | grep \&.pdf\&)&);
std::string noNewlines(R&(\n\n)&);
std::string cmd(R&(ls /home/docs | grep &.pdf&)&);
raw string的分隔符可以灵活指定,
用户可以指定各种各样的分隔符,原则就是不跟raw string text中的字符不相冲突即可,
例如下面的例子
std::regex re1(R&!(&operator\(\)&|&operator-&&)!&); /// &operator()&| &operator-&&
std::regex re2(R&xyzzy(&\([A-Za-z_]\w*\)&)xyzzy&);
/// &(identifier)&
5、变参模板,模板参数可以像printf一样变参了,不过我模板用的较少,感觉会用到这个的情况也不多,就不多介绍了。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致

我要回帖

更多关于 移动网上营业厅改套餐 的文章

 

随机推荐