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 = 10 // 错误,auto临时变量的语义在C++ 11中已不存在
auto a = 10
auto c = ‘A‘
auto s("hello");
vector<int> vctTemp;
auto it = vctTemp.begin();
auto ptr = [](){ cout << "hello world" << endl; };
1 template <typename T1, typename T2>
2 auto compose(T1 t1, T2 t2) -> decltype(t1 + t2)
3 {
4    return t1+t2;
5 }
6 auto v = compose(2, 3.14); // v‘s type is double

注意:auto并不能作为函数的返回类型,但是能用auto去代替函数的返回类型,当然,在这种情况下,函数必须有返回值才可以。auto不会告诉编译器去推断返回值的实际类型,它会通知编译器在函数的末段去寻找返回值类型。在上面的那个例子中,函数返回值的构成是由T1类型和T2类型的值,经过+操作符之后决定的。

自动化推导decltype

关于 decltype 是一个操作符,其可以评估括号内表达式的类型,其规则如下:

  1. 如果表达式e是一个变量,那么就是这个变量的类型。
  2. 如果表达式e是一个函数,那么就是这个函数返回值的类型。
  3. 如果不符合1和2,如果e是左值,类型为T,那么decltype(e)是T&;如果是右值,则是T。

原文给出的示例如下,我们可以看到,这个让的确我们的定义变量省了很多事。

decltype(&myfunc) pfunc = 0;
typedef decltype(&A::func1) type;

三、std::function

类模版 std::function是一种通用、多态的函数封装。std::function的实例可以对任何可以调用的目标进行存储、复制、和调用操作,这些目标包括函数、lambda表达式、绑定表达式、以及其它函数对象等。

用法示例:

①保存自由函数

1 void printA(int a)
2 {
3     cout<<a<<endl;
4 }
5
6  std::function<void(int a)> func;
7  func = printA;
8  func(2);

②保存lambda表达式

 1 std::function<void()> func_1 = [](){cout<<"hello world"<<endl;}; 2 func_1(); 

运行输出:hello world

③保存成员函数

 1 struct Foo {
 2     Foo(int num) : num_(num) {}
 3     void print_add(int i) const { cout << num_+i << ‘\n‘; }
 4     int num_;
 5 };
 6
 7  // 保存成员函数
 8     std::function<void(const Foo&, int)> f_add_display = &Foo::print_add;
 9     Foo foo(2);
10     f_add_display(foo, 1);

运行输出: 3

四、bind

bind是一组用于函数绑定的模板。在对某个函数进行绑定时,可以指定部分参数或全部参数,也可以不指定任何参数,还可以调整各个参数间的顺序。对于未指定的参数,可以使用占位符_1、_2、_3来表示。_1表示绑定后的函数的第1个参数,_2表示绑定后的函数的第2个参数,其他依次类推。

下面通过程序例子了解一下用法:

 1 #include <iostream>
 2 using namespace std;
 3 class A
 4 {
 5 public:
 6     void fun_3(int k,int m)
 7     {
 8         cout<<k<<" "<<m<<endl;
 9     }
10 };
11
12 void fun(int x,int y,int z)
13 {
14     cout<<x<<"  "<<y<<"  "<<z<<endl;
15 }
16
17 void fun_2(int &a,int &b)
18 {
19     a++;
20     b++;
21     cout<<a<<"  "<<b<<endl;
22 }
23
24 int main(int argc, const char * argv[])
25 {
26     auto f1 = bind(fun,1,2,3); //表示绑定函数 fun 的第一,二,三个参数值为: 1 2 3
27     f1(); //print:1  2  3
28
29     auto f2 = bind(fun, placeholders::_1,placeholders::_2,3);
30     //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f2 的第一,二个参数指定
31     f2(1,2);//print:1  2  3
32
33     auto f3 = bind(fun,placeholders::_2,placeholders::_1,3);
34     //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别有调用 f3 的第二,一个参数指定
35     //注意: f2  和  f3 的区别。
36     f3(1,2);//print:2  1  3
37
38
39     int n = 2;
40     int m = 3;
41
42     auto f4 = bind(fun_2, n,placeholders::_1);
43     f4(m); //print:3  4
44
45     cout<<m<<endl;//print:4  说明:bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的
46     cout<<n<<endl;//print:2  说明:bind对于预先绑定的函数参数是通过值传递的
47
48
49     A a;
50     auto f5 = bind(&A::fun_3, a,placeholders::_1,placeholders::_2);
51     f5(10,20);//print:10 20
52
53     std::function<void(int,int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);
54     fc(10,20);//print:10 20
55
56     return 0;
57 }

五、nullptr -- 空指针标识

空指针标识(nullptr)(其本质是一个内定的常量)是一个表示空指针的标识,它不是一个整数。(译注:这里应该与我们常用的NULL宏相区别,虽然它们都是用来表示空置针,但NULL只是一个定义为常整数0的宏,而nullptr是C++0x的一个关键字,一个内建的标识符。下面我们还将看到nullptr与NULL之间更多的区别。)

 1     char* p = nullptr;
 2     int* q = nullptr;
 3     char* p2 = 0;           //这里0的赋值还是有效的,并且p=p2
 4
 5     void f(int);
 6     void f(char*);
 7
 8     f(0);         //调用f(int)
 9     f(nullptr);   //调用f(char*)
10
11     void g(int);
12     g(nullptr);       //错误:nullptr并不是一个整型常量
13     int i = nullptr;  //错误:nullptr并不是一个整型常量
14 (译注:实际上,我们这里可以看到nullptr和NULL两者本质的差别,NULL是一个整型数0,而nullptr可以看成是一个空指针。)

六、final 和 override

两者都是用在对于继承体系的控制。

final

用来标明被这个修饰符修饰的class/struct和虚函数已经是最终版本,无法被进一步继承.

override

override关键字用来表示在子类的函数一定重载自基类的同名同性质的虚函数或者纯虚函数,否则无法被编译.

 1 class Base
 2 {
 3 public:
 4     virtual void test(){}
 5     virtual void test2(int i) {}
 6     virtual void test3() const {}
 7 };
 8
 9 class D1:public Base
10 {
11     void test() override {}  //编译正确
12     void test2(float i) override {} //编译错误,参数不一致
13     void test3() override {} //编译错误,函数常量性不一致
14     void test4() override {} //编译错误,并不是重载父类虚函数
15 };

需要注意的一点是,final和override两者很有可能在C++ 98的代码里面被程序员大量的用在其他地方命名,因此C++ 11为了保持和之前代码的兼容性,所以这两个标记只有在修饰class/struct和函数的时候,才会被当成关键字。也就是说,在其他地方依然可以使用这两个字符命名成变量/函数/类/结构体.

比如:

 1 class Base
 2 {
 3 public:
 4     virtual void test()
 5     {
 6         int final = 1;
 7     }
 8     virtual void test2(int i) {}
 9     virtual void test3() const {}
10     virtual void override();
11 };
时间: 2024-12-06 10:39:42

C++ 11 Lambda表达式、auto、function、bind、final、override的相关文章

C++11 Lambda表达式简单解析

C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性, 建议去http://www.open-std.org/看看新标准! 很多语言都提供了 lambda 表达式,如 Python,Java 8 lambda 表达式可以方便地构造匿名函数,如果你的代码里面存在大量的小函数,而这些函数一般只被调用一次,那么不妨将他们重构成 lambda 表达式. C++11 的 lambda 表达式规范如下: [ capture ] ( params ) mutable

C++11 lambda 表达式解析

C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性,建议去这里,这里,这里,还有这里看看.本文作为 5 月的最后一篇博客,将介绍 C++11 的 lambda 表达式. 很多语言都提供了 lambda 表达式,如 Python,Java 8.lambda 表达式可以方便地构造匿名函数,如果你的代码里面存在大量的小函数,而这些函数一般只被调用一次,那么不妨将他们重构成 lambda 表达式. C++11 的 lambda 表达式规范如下: [ capt

Python Special Syntax 11: lambda表达式

lambdTesting=lambda x: x*3 print(lambdTesting(5)) 输出 15 像C#一样传递lambda表达式: def abc(t,a): return t(a) print(abc(lambdTesting,15)) 输出:45 Python Special Syntax 11: lambda表达式,布布扣,bubuko.com

C++11 Lambda 表达式

1. 匿名函数 匿名函数是一些拥有函数体,但没有函数名的函数.Lambda是一种与匿名函数相关的编程技术,但需要说明的是Lambda表达式得到的不是一个匿名函数,而是一个函数对象.MSDN:Lambda隐式定义函数对象类并构造该类类型的函数对象. 2. Lambda语法 C++11 Lambda 表达式

c++11——lambda表达式

lambda表达式 函数式编程的一个语法,有如下优点: (1)声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象.以更直接的方式写程序,好的可读性和可维护性. (2)简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散. (3)在需要的时间和地点实现功能闭包,使程序更灵活. lambda表达式基本概念和用法 lambda表达式定义了一个匿名函数,并且可以捕获一定范围的变量.lambda表达式的语法如下: [capture] (params) opt

C++11 lambda表达式(19篇C++11文章)

C++11引入了lambda表达式,使得程序员可以定义匿名函数,该函数是一次性执行的,既方便了编程,又能防止别人的访问. Lambda表达式的语法通过下图来介绍: 这里假设我们定义了一个如上图的lambda表达式.现在来介绍途中标有编号的各个部分是什么意思. Lambda表达式的引入标志,在‘[]’里面可以填入‘=’或‘&’表示该lambda表达式“捕获”(lambda表达式在一定的scope可以访问的数据)的数据时以什么方式捕获的,‘&’表示一引用的方式:‘=’表明以值传递的方式捕获,除

C++11 lambda表达式学习

lambda表达式是函数式编程的基础.咱对于函数式编程也没有足够的理解,因此这里不敢胡言乱语,有兴趣的可以自己查找相关资料看下.这里只是介绍C++11中的lambda表达式自己的认识.这里有参考文档http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2927.pdf 给出两个例子,可以看出lambda表达式的写法 [](int x, int y) { return x + y; } [](int x, int y) -> int {

C++11 lambda表达式在for_each和transform算法下的使用

以前,在lambda表达式没有进入标准的时候,对容器的遍历等涉及到使用函数指针的情况,一般人会懒得使用std::for_each,或std::transform,也许只是一个短短的几句话,却要单独写个函数,或函数对象,写的代码反而不如自己用for循环来的快. 但是,C++11引入了lambda表达式后,一切都变的简单了! 1.lambda表达式 lambda表达式是一个匿名函数,用它可以非常方便的表示一个函数对象,先简单说一下lambda表达式,下面这张图表示了C++11中lambda表达式的写

C++11 lambda 表达式作用在传统C回调函数上

//--std=c++11 #include <functional> #include <cstdio> typedef bool (*IS_X_NUM)(int); void show_x_num(int * array, int len, IS_X_NUM is_x_num) {     for(int i = 0; i < len; i++) {         if(is_x_num(array[i])) {             printf("%d