Qt5中使用lambda表達式

c11新特性中加入了lambda表達式,因此Qt 也支持ios

需在.pro文件中加入c++

CONFIG += c++11

例子:
 1    QString program = "C:/Windows/System32/cmd.exe";
 2     QStringList arguments;
 3     arguments << "/c" << "dir" << "C:\\";
 4     QProcess* cmdProcess = new QProcess;
 5     QObject::connect(cmdProcess, &QProcess::readyRead,[=](){
 6         QTextCodec *codec = QTextCodec::codecForName("GBK");
 7         QString dir = codec->toUnicode(cmdProcess->readAll());
 8         qDebug() << dir;
 9     });
10     cmdProcess->start(program, arguments);

 

 

一段簡單的Code函數

 

我也不是文藝的人,對於Lambda的歷史,以及Lambda與C++的那段淵源,我也不是很熟悉,技術人,講究拿代碼說事。this

 


複製代碼 代碼以下:spa

 


#include<iostream>
using namespace std;

int main()
{
int a = 1;
int b = 2;

auto func = [=, &b](int c)->int {return b += a + c;};
return 0;
}指針

 

 

 

當我第一次看到這段代碼時,我直接凌亂了,直接看不懂啊。上面這段代碼,若是你看懂了,下面的內容就當時複習了;若是看不懂了,就接着和我一塊兒總結吧。c++11

 

基本語法code

 

簡單來講,Lambda函數也就是一個函數,它的語法定義以下:對象

 


複製代碼 代碼以下:blog

 


[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也是一種重複。

 

Lambda的使用

 

對於Lambda的使用,說實話,我沒有什麼多說的,我的理解,在沒有Lambda以前的C++ , 咱們也是那樣好好的使用,並無對缺乏Lambda的C++有什麼抱怨,而如今有了Lambda表達式,只是更多的方便了咱們去寫代碼。不知道你們是否記得C++ STL庫中的仿函數對象,仿函數想對於普通函數來講,仿函數能夠擁有初始化狀態,而這些初始化狀態是在聲明仿函數對象時,經過參數指定的,通常都是保存在仿函數對象的私有變量中;在C++中,對於要求具備狀態的函數,咱們通常都是使用仿函數來實現,好比如下代碼:

 


複製代碼 代碼以下:

 


#include<iostream>
using namespace std;

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

class Calc
{
public:
Calc(int x, int y):m_x(x), m_y(y){}

int operator()(type i)
{
switch (i)
{
case add:
return m_x + m_y;
case sub:
return m_x - m_y;
case mul:
return m_x * m_y;
case divi:
return m_x / m_y;
}
}

private:
int m_x;
int m_y;
};

int main()
{
Calc addObj(10, 20);
cout<<addObj(add)<<endl; // 發現C++11中,enum類型的使用也變了,更「強」了
return 0;
}

 

 

 

如今咱們有了Lambda這個利器,那是否是能夠重寫上面的實現呢?看代碼:

 


複製代碼 代碼以下:

 


#include<iostream>
using namespace std;

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;
}

 

 

 

顯而易見的效果,代碼簡單了,你也少寫了一些代碼,也去試一試C++中的Lambda表達式吧。

 

關於Lambda那些奇葩的東西

 

看如下一段代碼:

 


複製代碼 代碼以下:

 


#include<iostream>
using namespace std;

int main()
{
int j = 10;
auto by_val_lambda = [=]{ return j + 1; };
auto by_ref_lambda = [&]{ return j + 1; };
cout<<"by_val_lambda: "<<by_val_lambda()<<endl;
cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl;

++j;
cout<<"by_val_lambda: "<<by_val_lambda()<<endl;
cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl;

return 0;
}

 

 

 

程序輸出結果以下:

 


複製代碼 代碼以下:

 


by_val_lambda: 11
by_ref_lambda: 11
by_val_lambda: 11
by_ref_lambda: 12

 


你想到了麼???那這又是爲何呢?爲何第三個輸出不是12呢?

 

在by_val_lambda中,j被視爲一個常量,一旦初始化後不會再改變(能夠認爲以後只是一個跟父做用域中j同名的常量),而在by_ref_lambda中,j仍然在使用父做用域中的值。因此,在使用Lambda函數的時候,若是須要捕捉的值成爲Lambda函數的常量,咱們一般會使用按值傳遞的方式捕捉;相反的,若是須要捕捉的值成成爲Lambda函數運行時的變量,則應該採用按引用方式進行捕捉。

 

再來一段更暈的代碼:

 


複製代碼 代碼以下:

 


#include<iostream>
using namespace std;

int main()
{
int val = 0;
// auto const_val_lambda = [=](){ val = 3; }; wrong!!!

auto mutable_val_lambda = [=]() mutable{ val = 3; };
mutable_val_lambda();
cout<<val<<endl; // 0

auto const_ref_lambda = [&]() { val = 4; };
const_ref_lambda();
cout<<val<<endl; // 4

auto mutable_ref_lambda = [&]() mutable{ val = 5; };
mutable_ref_lambda();
cout<<val<<endl; // 5

return 0;
}

 

 

 

這段代碼主要是用來理解Lambda表達式中的mutable關鍵字的。默認狀況下,Lambda函數老是一個const函數,mutable能夠取消其常量性。按照規定,一個const的成員函數是不能在函數體內修改非靜態成員變量的值。例如上面的Lambda表達式能夠當作如下仿函數代碼:

 


複製代碼 代碼以下:

 


class const_val_lambda
{
public:
const_val_lambda(int v) : val(v) {}
void operator()() const { val = 3; } // 常量成員函數

private:
int val;
};

 

 

 

對於const的成員函數,修改非靜態的成員變量,因此就出錯了。而對於引用的傳遞方式,並不會改變引用自己,而只會改變引用的值,所以就不會報錯了。都是一些糾結的規則。慢慢理解吧。

相關文章
相關標籤/搜索