【QT】3_3_1_Qt中lambda基础和使用(c++11)

作者:永恒0852永恒0852发布时间:2017-11-13 22:57
1.WHAT
        1)lambda 表达式(lambda expression)是一个匿名函数,lambda表达式基于数学中的 λ 演算得名。
            a)“λ演算”:见百度百科:https://baike.baidu.com/item/%CE%BB%E6%BC%94%E7%AE%97
            b)“λ演算”:λ(Lambda(大写Λ,小写λ)读音:lan b(m) da(兰亩达)['læ;mdə])演算是一套用于研究函数定义、函数应用和递归的形式系统。它由 Alonzo Church 和 Stephen Cole Kleene 在 20 世纪三十年代引入,Church 运用 lambda 演算在 1936 年给出 判定性问题 (Entscheidungsproblem) 的一个否定的答案。这种演算可以用来清晰地定义什么是一个可计算函数。
        2)C++11中的lambda表达式用于定义并创建匿名的函数对象,以简化编程工作。

2.HOW

        1)lambda表达式的基本构成:

1.png

            ①:[ ] 标识一个lambda的开始,这部分必须存在,不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义lambda为止时lambda所在作用范围内可见的局部变量(包括lambda所在类的this)(需要注意的是:lambda表达式之前定义的变量,才可以使用)。函数对象参数有以下形式:(a,b 是前面已经定义的变量)
                a):空。没有使用任何函数对象参数。
                b):=。函数体内可以使用lambda所在作用范围内所有可见的局部变量(包括lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)。
                c):&。函数体内可以使用lambda所在作用范围内所有可见的局部变量(包括lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)。
                d):this。函数体内可以使用lambda所在类中的成员变量。
                e):a。将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符
                f ):&a。将a按引用进行传递。
                g):a, &b。将a按值进行传递,b按引用进行传递。
                h):=,&a, &b。除a和b按引用进行传递外,其他参数都按值进行传递。
                i ):&, a, b。除a和b按值进行传递外,其他参数都按引用进行传递。

            ② 操作符重载函数参数
                标识重载的()操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递。
            ③ 可修改标示符
            mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)。
            ④ 错误抛出标示符
            exception声明,这部分也可以省略。exception声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用throw(int)
            ⑤ 函数返回值
            ->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
            ⑥ 是函数体
            {},标识函数的实现,这部分不能省略,但函数体可以为空。

        2)怎么使用lambda表达式:使用时,需要告诉编译器,这个是c++11的功能(qt:CONFIG +=c++11,g++:在编译的时候需要指定为 c++11)
            ①类内部使用:
//在类中的使用
class Test
{
public:
       int i = 0;
       void func(int x, int y)
       {
              //auto x1 = []{ return i; };                           //err, 没有捕获外部变量
              auto x2 = [=] { return i + x + y; };            //ok, 值传递方式捕获所有外部变量
              auto x3 = [=] { return i + x + y; };            //ok, 引用传递方式捕获所有外部变量
              auto x4 = [this] { return i; };                        //ok, 捕获this指针
              //auto x5 = [this]{ return i+x+y; };            //err, 没有捕获x, y
              auto x6 = [this, x, y] { return i + x + y; };//ok, 捕获this指针, x, y
              auto x7 = [this] { return i++; };               //ok, 捕获this指针, 并修改成员的值
       }
};

            ②普通函数(主函数)使用(vs2015)

int main()
{      
       //原始数据
       int a1 = 100; 
       int b1 = 200;
       //= 值传递
       auto p1 = [=](int a,int b)
       {
              //b1 = 100;                //默认的lambda表达式const修饰的,值传递不能修改外部捕获到的参数(即使修改了,也是内部的临时变量,也不能改变外部的b1
              a = 10;                           //可以修改形参的值(临时变量
              cout << "p1->"<< "a1="<< a1 << " b1=" << b1 <<endl;           //输出100,200
              cout << "p1->"<< " a=" << a << "  b=" << b <<endl;            //输出10,2
       };
       p1(1, 2);            //调用p1
       //& 引用传递
       auto p2 = [a1, &b1]()
       {
              //a1 = 1000;
              b1 = 2000;                 //引用传递能修改外部捕获到的参数
              cout << "p2->" << "a1=" << a1 << " b1=" << b1 << endl;        //输出100,2000
       };
       p2();
       cout << "外部->" << "a1=" << a1 << " b1=" << b1 << endl;             //输出100,2000
       system("pause");
       return EXIT_SUCCESS;

2.png

            ③QT中的槽函数使用,信号的处理方式如下:
                a)connect(信号发送者, 发送信号的对象发送的是什么信号, 信号接收者, 接收的对象进行信号处理);
                b)如上面格式所述,接受对象需要对信号进行处理,就需要指定我们定义好的(或标准的)槽函数,那么有了lambda表达式,就可以不用定义槽函数,而直接使用lambda表达式来对这个信号尽心处理。

                    如下案例:一个窗口发送了一个自定义信号,那么我们就可以直接使用lambda表达式对这个信号做出相应的处理。(案例是大小窗口的一部分)

//使用指针的方式获取数据
connect(&silw,&SilWiget::testSignal03,
[=](int *a)
{
cout <<"大窗口响应";
*a = 66666;
}

);
}
        3)注意事项
            ①lambda表达式,可以传递进来两部分参数,如果是[]方括号捕捉的外部变量,则对外部数据操作的权限取决于方括号里的符号,()圆括号是外部传递进来的形参
                a)“[=]”是以值传递的方式进行传递,在函数体中不能修改捕捉到的变量的值,如果需要修改需要是用“mutable”修饰(去掉const属性),但修改的数据也是只函数体内部的临时变量,而不是修改外部的实际变量。
                b)“[&]”是以引用传递的方式进行传递,在函数体中可以直接修改外部的变量。
            ②"( )" 形参的操作权限,和普通函数一样。

3.WHY
        1)Lambda 函数又称匿名函数,匿名函数就是没有名字的函数,函数没有名字也行?当然可以啦。有些函数如果只是临时一用,而且它的业务逻辑也很简单时,就没必要非给它取个名字不可。

        2)好比电影里面的群众演员,往往他们的戏份很少,最多是衬托主演,跑跑龙套,他们需要名字吗?不需要,因为他们仅仅只是临时出镜,下次可能就用不着了,所以犯不着费心思给他们每个人编个号取个名字,毕竟取个优雅的名字是很费劲的事情。

/*************************************************************
*   温馨提示:
*            为了不影响文章的可读性,本站图片均不自动加水印。
*            除非注明,文章均由"永恒0852"整理发布,欢迎转载。
*            否则转载请注明本文地址:http://www.yongheng0852.com/qt/45.html
**************************************************************/



评论