博客 / 詳情

返回

C++ lambda表達式

lambda表達式也稱匿名函數,c++11新增內容。

語法如下:

/*
參數説明:
capture list:    捕獲列表,是一個lambda所在函數中定義的局部變量列表
parameter list: 參數列表
return type:    返回類型
function body:  函數體
*/
[capture list] (parameter list) -> return type {function body}

lambda表達式可以理解為可調用的代碼單元,

可以忽略參數列表和返回類型,但必須永遠包含捕獲列表和函數體

    auto ret = []() {
        return 5;
    };
    cout << ret() << endl;

image.png


值捕獲

值捕獲的前提是變量可以拷貝。變量的值是在lambda創建時拷貝,而不是調用時拷貝,因此其修改不會影響到lambda內部對應的值。

默認情況下:如果以傳值方式捕獲外部變量,則在Lambda表達式函數體中不能修改該外部變量的值。

當按值的方式獲取外部變量時,是無法更改獲取過來的值的,除非使用mutable關鍵字聲明,就可以更改(更改的不是外部變量原本地址裏的值,而是lambda函數體內的副本);

int main()
{
    int num = 2;
    auto ret = [num] () { return num; };
    num += 2;
    cout << ret() << endl; //輸出 2
    cout << num << endl; //輸出 4
    return 0;
}

引用捕獲

當按引用的方式捕獲外部變量時,lambda函數體內可以更改此值,更改的是外部變量原本地址裏的值;

int main()
{
    int num = 2;
    auto ret = [&num] () { return num; };
    num += 2;
    cout << ret() << endl; //輸出 4
    cout << num << endl; //輸出 4
    return 0;
}

隱式捕獲

隱式捕獲有兩種方式,分別是[=]和[&]。[=]表示以值捕獲的方式捕獲外部變量,[&]表示以引用捕獲的方式捕獲外部變量

當按值的方式獲取外部變量時,是無法更改獲取過來的值的,除非使用mutable關鍵字聲明,就可以更改(更改的不是外部變量原本地址裏的值,而是lambda函數體內的副本);
當按引用的方式捕獲外部變量時,lambda函數體內可以更改此值,更改的是外部變量原本地址裏的值;

int main()
{
    int num = 2;

    //可以捕獲外部變量
    auto ret = [=] () { 
        return num; 
    };
    //會報錯 ,無法修改外部變量
    auto ret = [=]() {
        return num++;
    };
    

    //可以捕獲外部變量
    auto ret = [&]() {
        return num;
    };
    //可以法修改外部變量
    auto ret = [&]() {
        return num++;
    };
    return 0;
}

混合方式捕獲

lambda還支持混合方式捕獲,即同時使用顯示捕獲和隱式捕獲。

混合捕獲時,捕獲列表中的第一個元素必須是 = 或 &,此符號指定了默認捕獲的方式是值捕獲或引用捕獲 。

需要注意的是:顯示捕獲的變量必須使用和默認捕獲不同的方式捕獲。

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

    auto f1 = [=, &a]() { return a + b; };        //正確,默認值捕獲,顯示是引用捕獲
    auto f2 = [=, a]() { return a + b; };        //編譯出錯,默認值捕獲,顯示值捕獲,衝突了
    auto f3 = [&, a]() { return a + b; };        //正確,默認引用捕獲,顯示是引用捕獲
    auto f4 = [&, &a]() { return a + b; };        //編譯出錯,默認引用捕獲,顯示引用捕獲,衝突了

    return 0;
}

修改值捕獲的值

在Lambda表達式中,如果以傳值方式捕獲外部變量,則函數體中不能修改該外部變量,否則會引發編譯錯誤。

如果你希望被值捕獲的值被改變,就必須在參數列表首加上關鍵字mutable。

//語法
[capture list] (parameter list) mutable -> return type {function body}
int main()
{
    int num = 2;

    auto f1 = [num]()mutable { // 不會報錯
        num++;
        cout << num << endl;
    };

    auto f2 = [=]()mutable { // 不會報錯
        num++;
        cout << num << endl;
    };

    cout << num++ << endl;
    f1();
    f2();

    return 0;
}
  • 當按值的方式獲取外部變量時,是無法更改獲取過來的值的,除非使用mutable關鍵字聲明,就可以更改(更改的不是外部變量原本地址裏的值,而是lambda函數體內的副本);
  • 當按引用的方式捕獲外部變量時,lambda函數體內可以更改此值,更改的是外部變量原本地址裏的值;
  • 當在類中,lambda表達式捕獲this指針時,lambda函數體內可以直接改變該類中的變量,和類中的普通函數擁有一樣的權限。
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.