程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++中的Lambda表達式詳解

C++中的Lambda表達式詳解

編輯:關於C++

C++中的Lambda表達式詳解。本站提示廣大學習愛好者:(C++中的Lambda表達式詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C++中的Lambda表達式詳解正文


我是弄C++的

一向都在提示本身,我是弄C++的;然則當C++11出來這麼長時光了,我卻沒有隨著部隊走,發明很對不起本身的身份,也還好,發明本身也有段時光沒有寫C++代碼了。明天看到了C++中的Lambda表達式,固然用過C#的,然則C++的,一向沒有效,也不曉得怎樣用,便可憐的連Lambda語法都看不懂。好了,這裡就對C++中的Lambda停止一個簡略的總結,就算是對本身的一個交卸,我是弄C++的,我是一個C++ programmer。

一段簡略的Code

我也不是文藝的人,關於Lambda的汗青,和Lambda與C++的那段淵源,我也不是很熟習,技巧人,講求拿代碼說事。


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

當我第一次看到這段代碼時,我直接紛亂了,直接看不懂啊。下面這段代碼,假如你看懂了,上面的內容就其時溫習了;假如看不懂了,就接著和我一路總結吧。

根本語法

簡略來講,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也是一種反復。

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的成員函數,修正非靜態的成員變量,所以就失足了。而關於援用的傳遞方法,其實不會轉變援用自己,而只會轉變援用的值,是以就不會報錯了。都是一些糾結的規矩。漸漸懂得吧。

總結

關於Lambda這類器械,有的人用的異常爽,而有的人看著都不爽。仁者見仁,智者見智。不論怎樣樣,作為法式員的你,都要會的。這篇文章就是用來填補本身對C++ Lambda表達式的認知缺乏的錯誤,以避免今後在他人的代碼中看到了Lambda,還看不懂這類器械,那就丟年夜人了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved