最簡單的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