C++ 11 Lambda表达式、auto、function、bind、final、override
接触了cocos2dx 3.0,就必须得看C++ 11了。有分享过帖子:【转帖】漫话C++0x(四) —- function, bind和lambda。其实最后的Lambda没太怎么看懂。
看不懂没关系,会用就行。可惜是连用都要思考半天。其实,查找根源是定义没有搞明白。
以后买东西,用之前,先看说明书才是必要的。
---------------------------------开始正文粘贴-----------------------------------------
一、Lambda表达式
C++ 11中的Lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。Lambda的语法形式如下:
如上图所示Lambda分为以下几个部分:1、 [函数对象参数] ,2、(操作符重载函数参数), 3、mutable, 4、exception声明, 5、->返回值类型, 6、{函数体}。
当然也可以认为Lambda主要分为五个部分:[函数对象参数]、(操作符重载函数参数)、mutable或exception声明、->返回值类型、{函数体}。
下面分别进行介绍。
1、[函数对象参数],标识一个Lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:
1、空。没有使用任何函数对象参数。
2、=。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
3、&。函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
4、this。函数体内可以使用Lambda所在类中的成员变量。
5、a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。
6、&a。将a按引用进行传递。
7、a, &b。将a按值进行传递,b按引用进行传递。
8、=,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
9、&, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。
2、(操作符重载函数参数),标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。
3、mutable或exception声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。exception声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用throw(int)。
4、->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
5、{函数体},标识函数的实现,这部分不能省略,但函数体可以为空。
其实学习Lambda最好的资料还是MSDN,传送门:Lambda 表达式语法http://msdn.microsoft.com/zh-cn/library/dd293603.aspx
注意文中有一句:
Visual Studio 通过添加以下特性来增添 C++11 lambda 功能:
无状态 lambda 可通过任意调用约定完全转换为函数指针。
只要所有返回语句具有相同的类型,会自动推导比 { return expression; } 更复杂的 lambda 主体的返回类型。(这一特性现包含在拟建的 C++14 标准中。)
二、auto 关键字
C++ 11中引入的auto主要有两种用途:自动类型推断和返回值占位。
auto自动类型推断,用于从初始化表达式中推断出变量的数据类型。通过auto的自动类型推断,可以大大简化我们的编程工作。
因此,Lambda表达式和auto关键字合体之后,就可以非常方便的用类似如下的代码了:
- auto a; // 错误,没有初始化表达式,无法推断出a的类型
- auto int a = // 错误,auto临时变量的语义在C++ 11中已不存在
- auto a =
- auto c = 'A'
- auto s("hello");
- vector<int> vctTemp;
- auto it = vctTemp.begin();
- auto ptr = [](){ cout << "hello world" << endl; };
- template <typename T1, typename T2>
- auto compose(T1 t1, T2 t2) -> decltype(t1 + t2)
- {
- return t1+t2;
- }
- auto v = compose(, 3.14); // v's type is double
注意:auto并不能作为函数的返回类型,但是能用auto去代替函数的返回类型,当然,在这种情况下,函数必须有返回值才可以。auto不会告诉编译器去推断返回值的实际类型,它会通知编译器在函数的末段去寻找返回值类型。在上面的那个例子中,函数返回值的构成是由T1类型和T2类型的值,经过+操作符之后决定的。
关于 decltype
是一个操作符,其可以评估括号内表达式的类型,其规则如下:
- 如果表达式e是一个变量,那么就是这个变量的类型。
- 如果表达式e是一个函数,那么就是这个函数返回值的类型。
- 如果不符合1和2,如果e是左值,类型为T,那么decltype(e)是T&;如果是右值,则是T。
原文给出的示例如下,我们可以看到,这个让的确我们的定义变量省了很多事。
- decltype(&myfunc) pfunc = ;
- typedef decltype(&A::func1) type;
三、std::function
类模版 std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标进行存储、复制、和调用操作,这些目标包括函数、lambda表达式、绑定表达式、以及其它函数对象等。
用法示例:
①保存自由函数
- void printA(int a)
- {
- cout<<a<<endl;
- }
- std::function<void(int a)> func;
- func = printA;
- func();
②保存lambda表达式
运行输出:hello world
③保存成员函数
- struct Foo {
- Foo(int num) : num_(num) {}
- void print_add(int i) const { cout << num_+i << '\n'; }
- int num_;
- };
- // 保存成员函数
- std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
- Foo foo();
- f_add_display(foo, );
运行输出: 3
四、bind
bind是一组用于函数绑定的模板。在对某个函数进行绑定时,可以指定部分参数或全部参数,也可以不指定任何参数,还可以调整各个参数间的顺序。对于未指定的参数,可以使用占位符_1、_2、_3来表示。_1表示绑定后的函数的第1个参数,_2表示绑定后的函数的第2个参数,其他依次类推。
下面通过程序例子了解一下用法:
- #include <iostream>
- using namespace std;
- class A
- {
- public:
- void fun_3(int k,int m)
- {
- cout<<k<<" "<<m<<endl;
- }
- };
- void fun(int x,int y,int z)
- {
- cout<<x<<" "<<y<<" "<<z<<endl;
- }
- void fun_2(int &a,int &b)
- {
- a++;
- b++;
- cout<<a<<" "<<b<<endl;
- }
- int main(int argc, const char * argv[])
- {
- auto f1 = bind(fun,,,); //表示绑定函数 fun 的第一,二,三个参数值为: 1 2 3
- f1(); //print:1 2 3
- auto f2 = bind(fun, placeholders::_1,placeholders::_2,);
- //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f2 的第一,二个参数指定
- f2(,);//print:1 2 3
- auto f3 = bind(fun,placeholders::_2,placeholders::_1,);
- //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f3 的第二,一个参数指定
- //注意: f2 和 f3 的区别。
- f3(,);//print:2 1 3
- int n = ;
- int m = ;
- auto f4 = bind(fun_2, n,placeholders::_1);
- f4(m); //print:3 4
- cout<<m<<endl;//print:4 说明:bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的
- cout<<n<<endl;//print:2 说明:bind对于预先绑定的函数参数是通过值传递的
- A a;
- auto f5 = bind(&A::fun_3, a,placeholders::_1,placeholders::_2);
- f5(,);//print:10 20
- std::function<void(int,int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);
- fc(,);//print:10 20
- return ;
- }
五、nullptr -- 空指针标识
空指针标识(nullptr)(其本质是一个内定的常量)是一个表示空指针的标识,它不是一个整数。(译注:这里应该与我们常用的NULL宏相区别,虽然它们都是用来表示空置针,但NULL只是一个定义为常整数0的宏,而nullptr是C++0x的一个关键字,一个内建的标识符。下面我们还将看到nullptr与NULL之间更多的区别。)
- char* p = nullptr;
- int* q = nullptr;
- char* p2 = ; //这里0的赋值还是有效的,并且p=p2
- void f(int);
- void f(char*);
- f(); //调用f(int)
- f(nullptr); //调用f(char*)
- void g(int);
- g(nullptr); //错误:nullptr并不是一个整型常量
- int i = nullptr; //错误:nullptr并不是一个整型常量
- (译注:实际上,我们这里可以看到nullptr和NULL两者本质的差别,NULL是一个整型数0,而nullptr可以看成是一个空指针。)
六、final 和 override
两者都是用在对于继承体系的控制。
final
用来标明被这个修饰符修饰的class/struct和虚函数已经是最终版本,无法被进一步继承.
override
override关键字用来表示在子类的函数一定重载自基类的同名同性质的虚函数或者纯虚函数,否则无法被编译.
- class Base
- {
- public:
- virtual void test(){}
- virtual void test2(int i) {}
- virtual void test3() const {}
- };
- class D1:public Base
- {
- void test() override {} //编译正确
- void test2(float i) override {} //编译错误,参数不一致
- void test3() override {} //编译错误,函数常量性不一致
- void test4() override {} //编译错误,并不是重载父类虚函数
- };
需要注意的一点是,final和override两者很有可能在C++ 98的代码里面被程序员大量的用在其他地方命名,因此C++ 11为了保持和之前代码的兼容性,所以这两个标记只有在修饰class/struct和函数的时候,才会被当成关键字。也就是说,在其他地方依然可以使用这两个字符命名成变量/函数/类/结构体.
比如:
- class Base
- {
- public:
- virtual void test()
- {
- int final = ;
- }
- virtual void test2(int i) {}
- virtual void test3() const {}
- virtual void override();
- };
C++ 11 Lambda表达式、auto、function、bind、final、override的更多相关文章
- C++11 lambda 表达式
C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性,建议去这里,这里,这里,还有这里看看.本文作为 5 月的最后一篇博客,将介绍 C++11 的 lamb ...
- C++11 lambda 表达式解析
C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性,建议去这里,这里,这里,还有这里看看.本文作为 5 月的最后一篇博客,将介绍 C++11 的 lamb ...
- 详解 C++11 lambda表达式
详解 C++11 lambda表达式 lambda表达式是函数式编程的基础.咱对于函数式编程也没有足够的理解,因此这里不敢胡言乱语,有兴趣的可以自己查找相关资料看下.这里只是介绍C++11中的la ...
- C++11 — lambda表达式(匿名函数)
C++11中lambda表达式的基本语法格式为: [capture](parameters) -> return_type { /* ... */ } 其中 [] 内为外部变量的传递方式: [] ...
- c++11——lambda表达式
lambda表达式 函数式编程的一个语法,有如下优点: (1)声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象.以更直接的方式写程序,好的可读性和可维护性. (2) ...
- C++ 11 Lambda表达式
C++11的一大亮点就是引入了Lambda表达式.利用Lambda表达式,可以方便的定义和创建匿名函数.对于C++这门语言来说来说,“Lambda表达式”或“匿名函数”这些概念听起来好像很深奥,但很多 ...
- C++11 Lambda表达式简单解析
C++11 新增了非常多特性,lambda 表达式是当中之中的一个.假设你想了解的 C++11 完整特性, 建议去http://www.open-std.org/看看新标准! 非常多语言都提供了 la ...
- C++ 11 Lambda表达式!!!!!!!!!!!
C++11的一大亮点就是引入了Lambda表达式.利用Lambda表达式,可以方便的定义和创建匿名函数.对于C++这门语言来说来说,“Lambda表达式”或“匿名函数”这些概念听起来好像很深奥,但很多 ...
- 转:C++ 11 Lambda表达式
转:https://www.cnblogs.com/DswCnblog/p/5629165.html C++11的一大亮点就是引入了Lambda表达式.利用Lambda表达式,可以方便的定义和创建匿名 ...
随机推荐
- 执行Android项目时指定特定的AVD进行測试
一个Androidproject空间能够创建一个或多个AVD来对指定的Android项目进行測试,假设仅仅创建了一个AVD则执行Android项目时自然启动该AVD,但是假设创建了多个AVD那么我们该 ...
- LR杂记 - 性能測试指标及经常使用的监控工具
监控指标 性能測试通常须要监控的指标包含: 1.serverLinux(包含CPU.Memory.Load.I/O). 2.数据库:1.Mysql 2.Oracle(缓存命中.索引.单条SQL性能.数 ...
- 【redis】常用命令
三.常用命令 1)连接操作命令 quit:关闭连接(connection) auth:简单密码认证 help cmd: 查看cmd帮助,例如:help quit ...
- PHP生成缩略图、加水印
<?php class ThumbWaterImages{ /** * 生成缩略图/加水印 * classname ThumbWaterImages * datetime:2015-1-15 * ...
- Java annotation 自定义注释@interface的用法
最近看到很多项目都是用了自定义注解,例如 1.什么是注解? 元数据(metadata),就是指数据的数据,元数据是描述数据的,就像数据库中的,表的字段,每一个 字段描述这个字段下面·的数据的含义,j2 ...
- android语音识别技术
今天从网上找了个例子实现了语音识别,个人感觉挺好玩的,就把代码贴出来与大家分享下: Android中主要通过RecognizerIntent来实现语音识别,其实代码比较简单,但是如果找不到设置,就 ...
- Python2 元组 cmp() 方法
描述 Python2 元组 cmp() 方法用于比较两个元组,如果 T1< T2返回 -1, 如果 T1== T2返回 0, 如果 T1> T2返回 1. 语法 cmp() 方法语法: c ...
- python标准库介绍——1 os详解
== os 模块 == ``os`` 模块为许多操作系统函数提供了统一的接口. 这个模块中的大部分函数通过对应平台相关模块实现, 比如 ``posix`` 和 ``nt. os`` 模块会在第一次导入 ...
- django中跨app引用model
可能是自己水平的原因,总感觉跨django中app引用有点怪怪的,所以在自己没有达到另一个级别之前就先把正确的解决 方案记一下吧. 一.django中跨app引用model,以app02中的model ...
- php序列化与反序列化时字符集不一致问题的解决办法
今天的用PHP的时候无意的出现了用unserialize()函数转换老是返回false,我确认我的字符串是没错的,测试了很多次还是一样,没办法,启用了error_reporting(E_ALL)启用错 ...