拉姆达Lambda表达式以及Qt使用【匿名函数】

 

0、概述
格式:[capture](parameters) mutable ->return-type{statement}

也就是所谓的匿名函数

1、简单格式

auto f = [] {

    std::cout << "this is lambda" <<std::endl;
}
f();

2、直接调用

[] {

    std::cout << "this is lambda" <<std::endl;
} ();

3、带参数

auto f = [] (const std::string& s){

    std::cout << "this is lambda :" << s <<std::endl;
}
f("Im lambda.");

4、带返回值

[] {

    return 100;//未指定返回类型,这里默认为100
}
f();

5、指定返回类型

auto f = [] () -> double {

    return 100;
}
f();

6、访问外部作用域

int x=100;
int y=200;
auto f = [x,&y] {
    ++x;//x是值传递,不能这样,编译不过
    ++y;//y是引用传递,可以这样
}
x++,y++; f();

只有引用传递才能在lambda表达式中修改值,比如最后y=202;如果是值传递,那么表达式之中的x的初始值就是表达式定义时的值=100

7、可以改变值传递的值

int x=100;
auto f = [x]() mutable {
    ++x;//x是值传递,但是可以这样写
}
f();

 

8、QTimer使用

QTimer::singleShot(VALUE_300,NULL,[=]()

{

  updateSlot(SQL_CODE_12);

});

[]代表这是拉姆达函数,=代表是值传递,()代表入参这里没有,{}是函数体

 

9、按钮使用【有信号发送者也有信号接收者】

QDialog* log = new QDialog(this);
QPushButton* okBtn = new QPushButton(log);
QHBoxLayout* hLayout = new QHBoxLayout();
hLayout->addWidget(okBtn);
log->setLayout(hLayout);
QObject::connect(okBtn, &QPushButton::clicked,log,[=]()
{
      log->done(1);
});
if(1==log->exec())
{
    //...
}

注意核心就是不要写SIGNAL和SLOT,用对象类名表示

1).[var]表示值传递方式捕捉变量var;
2).[=]表示值传递方式捕捉所有父作用域的变量(包括this);
3).[&var]表示引用传递捕捉变量var;
4).[&]表示引用传递方式捕捉所有父作用域的变量(包括this);
5).[this]表示值传递方式捕捉当前的this指针。

 

10、QComboBox使用【有信号发送没有接收】

connect(box,&QComboBox::currentTextChanged,[](QString){});

注意这个信号必须是非重载的,否则会报错

 

 如果是重载需要转化

 

 

connect(box,static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),[](int){});

 

 

参考:https://www.cnblogs.com/rainbow70626/p/10328143.html

 

11、lamuda返回值

默认auto值

auto isByteType = [=] () {
    if(oneCmd.isByte)
        return "字节";
    else
        return "字符串";
};
qDebug()<<isByteType();

指定返回类型是QString或其他类型

auto isByteType = [=]()->QString {
    if(oneCmd.isByte)
        return "字节";
    else
        return "字符串";
};
qDebug()<<isByteType();

注意使用的时候要用括号,相当于这是个函数,而不是变量

 

12、排序

QList<int> list{3, 1, 2};
qSort(list.begin(),  list.end(),  [](int left, int right)->bool {
    return left < right;
    }
);

 

 

13、for循环

QList<int> list{1, 2, 3};
std::for_each(list.begin(),  list.end(),  [](int i) { 
    ...
});

参考:http://www.qtbig.com/page/13/

 

 

14、注意捕获列表里用引用时的问题


std::set<NetworkInfo> networks;
...

for
(auto it : networks){ QCheckBox* cbSwitch = new QCheckBox(ui->tableWidget); cbSwitch->setChecked(it.isRuning); cbSwitch->setText(QStringLiteral("开关网络")); QObject::connect(cbSwitch, QCheckBox::clicked, [&](bool isChecked){ qDebug()<<it.localPort; if(isChecked){ Devices::getInstance()->startDeviceByPort(it.localPort); }else{ Devices::getInstance()->stopDeviceByPort(it.localPort); }
});
}

QObject::connect(cbSwitch, QCheckBox::clicked, [&](bool isChecked)。。。

假设这里用的是引用传递,在函数体里会用到参数isChecked,和其他的变量,注意这个isChecked参数用引用方式传进去没问题,但是如果用到了其他变量如和这个it,那么真正在运行的时候,编译器还是记住的是it刚初始化的时候的地址,而又要求用引用传递,此时变量自然的就变成了空指针

解决:使用值传递 QObject::connect(cbSwitch, QCheckBox::clicked, [=](bool isChecked)。。。

 

15、拉姆达函数的实现原理

https://www.zhihu.com/question/436748893/answer/1653841635

 

16、例子:创建水平线和垂直线

/*此函数对象用于创建指定个数的标记线,参数1:[方向] 参数2:[个数]*/
std::function<void(Qt::Orientation, int)> fCreateMarkLine = [this](Qt::Orientation o, int count){
    for(int i=VALUE_0; i<count; ++i)
    {
       //create line
    }
};
fCreateMarkLine(Qt::Vertical, MarkLine_Vertical_Count);                         //创建垂直线
fCreateMarkLine(Qt::Horizontal, MarkLine_Horizontal_Count);                     //创建水平线

 

posted @ 2019-06-21 20:23  朱小勇  阅读(2126)  评论(0编辑  收藏  举报