C++ lambda

最簡單的lambda:git

int main()
{
    auto lambda = []{};
    lambda();
}

讓lambda更有用,就要捕捉局部變量。github

#include <stdio.h>
int main()
{
    int x = 1;
    
    auto lambda = [x] { 
        printf("x=%d",x); 
    }; 

    lambda();
}

[x]是按值方式的捕捉,並且lambda對應的那個可調用的方法,是const。能夠腦補這個等價物:函數

#include <stdio.h>
int main()
{
    int x=1;
    
    class unnamed_functor{
    public:
        unnamed_functor(int arg): x{arg}{}
        void operator()() const{
// x=2; 錯誤,const函數內不能修改爲員變量 printf(
"x=%d",x); } int x; }; unnamed_functor lambda{x}; lambda(); }

能夠使用mutable從新標記lambda函數,這個標記會清除const標記。例如:this

#include <stdio.h>
int main()
{
    int x = 1;
    
    auto lambda = [x] mutable{ 
        x=2;
        printf("in lambda x=%d\n",x); 
    }; 

    lambda();

    printf("x=%d\n",x); 
}

[&y]是按照引用方式捕捉局部變量。例如:spa

#include <stdio.h>
int main()
{
    int x=1, y= 2;
    
    auto lambda = [x, &y] { 
        y=3;
        printf("in lambda y=%d\n",y); 
    }; 

    lambda();

    printf("y=%d\n",y); 

}

可見,按照引用方式捕捉的局部變量,不用標記mutable也能更改y值。腦補以下僞代碼:指針

#include <stdio.h>
int main()
{
    int x=1,y=2 ;
    
    class unnamed_functor{
    public:
        unnamed_functor(int x_, int& y_): x{x_},y(y_){}
        void operator()() const{
            // x=2; 錯誤,const函數內不能修改爲員變量
            y=3;
            printf("in lambda y=%d\n",y);  
        }
        int x;
        int& y;
    }; 
    
    unnamed_functor lambda(x,y);
    lambda();

    printf("y=%d\n",y); 
}

這裏有個驚人的知識盲點,const成員函數能修改引用數據成員。仔細分析一下,const成員函數,關鍵意圖是不更改對象的狀態。對於int& y數據成員,就是不能更改此引用指向的對象。
當檢查y=3時,並無改變y所指向的對象(引用的本質是指針或者對象地址),所以與const不矛盾。這就解釋了lambda不用加mutable就能搞定引用捕捉的局部變量的修改問題。code

lambda做爲一個Callable,能夠接受任意調用參數:對象

int main(){
    int x=1;
    auto lambda = [x](int arg){ return x+arg; }
    std::cout << lambda(2); // show 3
}

C++14開始,lambda能有本身的內部狀態變量了。從前只有兩個狀態來源:[]捕捉的局部變量( automatic storage duaration 不能是全局變量)()捕捉的調用參數。
例如:blog

#include <stdio.h>

auto generator = [x = 0] () mutable {
  return x++;
};

int main()
{
    auto a = generator(); // == 0
    auto b = generator(); // == 1
    auto c = generator(); // == 2
}

腦補一下這個東西的等價物:get

#include <stdio.h>

class generator{
public:
    generator():x(0){}
    int operator()(){
        return x++;
    }
    int x;
};

int main()
{
    auto a = generator(); // == 0
    auto b = generator(); // == 1
    auto c = generator(); // == 2
}

lambda捕捉能力進一步加強,能夠捕捉任意的表達式。考慮以下問題:

#include <stdio.h>
#include <memory>

int main()
{
    auto p = std::make_unique<int>(1);
    //auto q = p; error:不能copy
    //auto k = std::move(p); ok: 能move copy
    
    auto lambda = [p] { 
        //...
    };
}

顯然,傳值方式失敗了,由於unique_ptr不支持copy。爲此,使用C++14的新語法:

#include <stdio.h>
#include <memory>

int main()
{
    auto p = std::make_unique<int>(1);
    //auto q = p; error:不能copy
    //auto k = std::move(p); ok: 能move copy
    auto lambda = [k=std::move(p)] { 
        //...
    };
}

lambda捕捉this指針的語法:

#include <stdio.h>
#include <memory>

struct MyObj {
  
    int value{ 123 };
    MyObj() = default;
    MyObj(const MyObj& other){
        value = other.value;
        printf("MyObj(const MyObj& other) \n");
    }
    
    auto getValueCopy() {
      return [*this] { return value; };
    }
    auto getValueRef() {
       return [this] { value=111; return value; };
    }
};

int main()
{

    MyObj mo;
    auto valueCopy = mo.getValueCopy();
    auto valueRef = mo.getValueRef();
    mo.value = 321;
    valueCopy(); // 123
    valueRef(); // 321
    
    printf("%d\n", mo.value);
    
}

參考:https://github.com/AnthonyCalandra/modern-cpp-features#lambda-capture-this-by-value

相關文章
相關標籤/搜索