標籤:文法 cto https 接受 資料 問題: named printf 檢查
最簡單的lambda:
int main(){ auto lambda = []{}; lambda();}
讓lambda更有用,就要捕捉局部變數。
#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標記。例如:
#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]是按照引用方式捕捉局部變數。例如:
#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就能搞定引用捕捉的局部變數的修改問題。
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 不能是全域變數)()捕捉的調用參數。
例如:
#include <stdio.h>auto generator = [x = 0] () mutable { return x++;};int main(){ auto a = generator(); // == 0 auto b = generator(); // == 1 auto c = generator(); // == 2}
腦補一下這個東西的等價物:
#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
C++ lambda