Lambda表达式以及在QT5信号槽函数connect中的应用

Lambda基本语法

简单来说,Lambda函数也就是一个匿名函数,类似于object -c里面的一个代码块block语法,能够在调用语句后面马上列出要执行的代码,不需要预先声明。它的语法定义如下:

[capture](parameters) mutable->return-type{statement} 

1.[capture]:捕捉列表。捕捉列表总是出现在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也是一种重复。

在QT5 connect函数中的应用:

我们都知道Qt5中允许信号和槽的参数数目不一致:槽函数的参数数目可以比信号的参数少。这是因为,我们信号的参数实际是作为一种返回值。正如普通的函数调用一样,我们可以选择忽略函数返回值,但是不能使用一个并不存在的返回值。如果槽函数的参数数目比信号的多,在槽函数中就使用到这些参数的时候,实际这些参数并不存在(因为信号的参数比槽的少,因此并没有传过来),函数就会报错。

然而,有一种情况,槽函数的参数可以比信号的多,那就是槽函数的参数带有默认值。比如,我们的Newspaper和Reader有下面的代码:

// Newspaper
signals:
    void new Paper(const QString& name);
// Reader
    void receiveNewspaper(const QString& name,const QDate& date=QDate::currentDate());

虽然Reader::receiveNewspaper()的参数数目比Newspaper::newPaper()多,但是由于Reader::receiveNewspaper()后面一个参数带有默认值,

所以该参数不是必须提供的。但是,如果你按照下面的写法,比如如下的代码:

connect(&newspaper,
        static_cast<void (Newspaper:: *)(const QString &)>(&Newspaper::newPaper),
        &reader,
        static_cast<void (Reader:: *)(const QString &, const QDate & = QDate::curentDate())>(&Reader::receiveNewspper));

你会得到一个断言错误:The slot requires more arguments than the signal provides.

我们不能在函数指针中使用函数参数的默认值。这是 C++ 语言的限制:参数默认值只能使用在直接地函数调用中。当使用函数指针取其地址的时候,默认参数是不可见的!
当然,此时你可以选择 Qt 4 的连接语法。如果你还是想使用 Qt 5 的新语法,目前的办法只有一个:Lambda 表达式。

于是,我们的代码就变成了:

connect(&newspaper,
        static_cast<void(Newspaper::*)(const QString&)>(&Newspaper::newPaper),
         [=](const QString& name){/* Your code here. */});
此时信号发出后没有接收者,只执行Lambda表达式这个匿名函数里的操作。这也是connect函数的一个重载,最后一个参数是 Functor 类型。
这个类型可以接受 static 函数、全局函数以及 Lambda 表达式。

猜你喜欢

转载自blog.csdn.net/zhouchunyue/article/details/79753235