C++ Lambda与connect

13 篇文章 1 订阅

Lambda简介:

c11新特性中加入了lambda表达式,所以Qt5.0 也支持,需在.pro文件中加入   CONFIG += c++11;

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也是一种重复。

 

 

typedef enum
{
add = 0,
sub,
mul,
divi
}type;

int main()
{
int a = 10;
int b = 20;

auto func = [=](type i)->int {
switch (i)
{
case add:
return a + b;
case sub:
return a - b;
case mul:
return a * b;
case divi:
return a / b;
}
};

cout<<func(add)<<endl;
}


Qt4的信号槽连接方式,以及Qt5新版的连接方式,简单演示一下lambda表达式的使用方式

代码如下:

 
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
 
    // 传统Qt是连接方式
    // 传统Qt4连接方式为 信号发送者,信号,信号接受者,处理函数
    QObject::connect(ui->pushButton,SIGNAL(clicked(bool)),this,SLOT(qT4_slot()));
 
    //Qt5连接方式
    //其实这么写的方式和Qt4没有啥却别,只是在Qt4 中引用了信号槽,在简单的使用时没有问题,但是在庞大的工程中,信号和曹 仅仅是宏替换,在编译的时候没有安全监测
    //Qt5的新方法,在编译的时候就会有监测,如果我们手误操作失误,就会出现问题
    QObject::connect(ui->pushButton_2,&QPushButton::clicked,this,&Widget::qT5_slot);

    //Qt5 Lambda表达式
    //这里需要注意 Lambda表达式是C++ 11 的内容,所以,需要再Pro项目文件中加入 CONFIG += C++ 11
    QObject::connect(ui->pushButton_3,&QPushButton::clicked,[=](){qDebug()<<"lambda 表达式";});
}
 
Widget::~Widget()
{
    delete ui;
}
 
void Widget::qT4_slot()
{
    qDebug()<< "This is Qt 4 Connect method";
}
 
void Widget::qT5_slot()
{
    qDebug()<< "This is Qt 5 Connect method";
}

 

 

 

在connect中使用lambda实现高效的信号/槽关联

 

如果编译器不支持c++ 11可变参数模板,则信号或槽中的参数数量限制为6;如果多参数需要传递,可以考虑Lambda;

 

在Qt中,使用QCoreApplication::connect()函数连接信号(signal)与槽(slots)的功能。
以下是connect函数的三种重载形式:

static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);

static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,const QObject *receiver, const QMetaMethod &method,Qt::ConnectionType type = Qt::AutoConnection);

inline QMetaObject::Connection connect(const QObject *sender, const char *signal,const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;

可以在函数声明中明显看出各个形参对应的意义,分别是[信号发送者,信号,接收者,槽],比如需要实现一个widget中点击button关闭窗口的功能,在Qt4这等老版本中,connect的写法是这样的:

connect(button,SIGNAL(QPushButton::cliked()),widget,SLOT(QWidget::close()));
  •  

每次都要添加SIGNAL/SLOT修饰符就显得很麻烦,所以在Qt5中,改进了connect的写法,可以直接用&代替修饰符

connect(button,&QPushButton::cliked,widget,&QWidget::close);
  • 这样的写法更简洁但是有一个问题就是无法向signal/slot函数传参,只能对无参版本的信号/槽生效,所以在有参数的情况下,只能选用第一种写法。

connect函数中,还有一个重要的限制!在传参的情况下,slot函数的参数个数一定要小于等于signal函数的参数个数,这样当signal函数是clicked()这样的无参形式时,我们不能与带参数的slot函数进行关联,这就意味着:如果我们想通过点击一个按钮实现一个较为复杂的功能,而这个功能的实现必须按需将实参传入slot函数,那么用传统的connect方法时行不通的。

在Qt5的新版本中,connect函数添加了对lambda的支持!——可以用lambda替代signal/slot函数。

这一feature的引进大大简化了slot函数的实现,更自由地扩充其功能,并且可以不受signal参数的影响(因为lambda可以捕获参数)而且connect的形式也进一步精简了。

比如我希望在点击一个button时,实现数据库的更新,页面的跳转,然后页面的关闭,那么只需要这么写:

connect(button,&QPushButton::cliked,[this,new_data,new_page]{
  UpdateDatabase(new_data);
  OpenNewPage(new_page);
  close();
});
  • 甚至连信号的接受者都不用指定了。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值