<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
lambda表示式又稱為匿名錶示式,是C11提出的新語法。[]儲存lambda表示式要捕獲的值,()內的引數為形參,可供外部呼叫傳值。lambda表示式可以直接呼叫
// 1 匿名呼叫 [](string name) { cout << "this is anonymous" << endl; cout << "hello " << name << endl; }("zack");
上述程式碼定義了一個匿名函數後直接呼叫。我們可以通過auto初始化一個變數儲存lambda表示式
// 2 通過auto賦值 auto fname = [](string name) { cout << "this is auto " << endl; cout << "hello " << name << endl; }; fname("Rolin");
通過auto定義fname,然後儲存了lambda表示式,之後呼叫fname即可。也可以通過函數指標的方式接受lambda表示式
typedef void (*P_NameFunc)(string name); // 3 函數指標 P_NameFunc fname2 = [](string name) { cout << "this is P_NameFunc " << endl; cout << "hello " << name << endl; }; fname2("Vivo");
P_NameFunc定義了fname2函數指標接受了lambda表示式。也可以通過function物件接受lambda表示式,function類是C11新增的語法。
// 4 function function<void(string)> funcName; funcName = [](string name) { cout << "this is function " << endl; cout << "hello " << name << endl; }; funcName("Uncle Wang");
用一個function物件接受了lambda表示式,同樣可以呼叫該function物件funcName達到呼叫lambda的效果。
1 值捕獲
int age = 33; string name = "zack"; int score = 100; string job = "softengineer"; //值捕獲 [age, name](string name_) { cout << "age is " << age << " name is " << name << " self-name is " << name_ << endl; }("Novia");
上述lambda表示式捕獲了age和name,是以值的方式來捕獲的。所以無法在lambda表示式內部修改age和name的值,如果修改age和name,編譯器會報錯,提示無法修改const常數,因為age和name是以值的方式被捕獲的。
2 參照捕獲
int age = 33; string name = "zack"; int score = 100; string job = "softengineer"; [&age, &name](string name_) { cout << "age is " << age << " name is " << name << " self-name is " << name_ << endl; name = "Xiao Li"; age = 18; }("Novia");
[]裡age和name前邊新增了&,此時age和name是以參照方式捕獲的。所以可以在lambda表示式中修改age和name的值。
C++的lambda表示式雖然可以捕獲區域性變數的參照,達到類似閉包的效果,但不是真的閉包,golang和python等語言通過閉包捕獲區域性變數後可以增加區域性變數的宣告週期,C++無法做到這一點,所以下面的呼叫會出現崩潰。
vector<function<void(string)>> vec_Funcs; void use_lambda2() { int age = 33; string name = "zack"; int score = 100; string job = "softengineer"; vec_Funcs.push_back([age, name](string name_) { cout << "this is value catch " << endl; cout << "age is " << age << " name is " << name << " self-name is " << name_ << endl; }); //危險,不要捕獲區域性變數的參照 vec_Funcs.push_back([&age, &name](string name_) { cout << "this is referenc catch" << endl; cout << "age is " << age << " name is " << name << " self-name is " << name_ << endl; }); } void use_lambda3() { for (auto f : vec_Funcs) { f("zack"); } } int main(){ use_lambda2(); use_lambda3(); }
use_lambda2中將lambda表示式儲存在function型別的vector裡,當use_lambda2結束後,裡邊的區域性變數都被釋放了,而vector中的lambda表示式還儲存著區域性變數的參照,在呼叫use_lambda3時呼叫lambda表示式,此時存取區域性變數已經被釋放了,所以導致程式崩潰。
3 全部用值捕獲,name用參照捕獲
int age = 33; string name = "zack"; int score = 100; string job = "softengineer"; [=, &name]() { cout << "age is " << age << " name is " << name << " score is " << score << " job is " << job << endl; name = "Cui Hua"; }();
通過=表示所有變數都以值的方式捕獲,如果希望某個變數以參照方式捕獲則單獨在這個變數前加&。
4 全部用參照捕獲,只有name用值捕獲
int age = 33; string name = "zack"; int score = 100; string job = "softengineer"; [&, name]() { cout << "age is " << age << " name is " << name << " score is " << score << " job is " << job << endl; }();
通過&方式表示所有變數都已參照方式捕獲,如果希望某個變數以值方式捕獲則單獨在這個變數前加=。
我們可以用function儲存形參和返回值相同的一類函數指標,可呼叫物件,lambda表示式等。
void use_function() { list<function<void(string)>> list_Funcs; //儲存函數物件 list_Funcs.push_back(FuncObj()); //儲存lambda表示式 list_Funcs.push_back([](string str) { cout << "this is lambda call " << str << endl; }); //儲存全域性函數 list_Funcs.push_back(globalFun); for (const auto &f : list_Funcs) { f("hello zack"); } }
C11同樣提供了bind操作,將原函數的幾個引數通過bind繫結傳值,返回一個新的可呼叫物件。
//繫結全域性函數 auto newfun1 = bind(globalFun2, placeholders::_1, placeholders::_2, 98, "worker"); //相當於呼叫globalFun2("Lily",22, 98,"worker"); newfun1("Lily", 22); //多傳引數沒有用,相當於呼叫globalFun2("Lucy",28, 98,"worker"); newfun1("Lucy", 28, 100, "doctor"); auto newfun2 = bind(globalFun2, "zack", placeholders::_1, 100, placeholders::_2); //相當於呼叫globalFun2("zack",33,100,"engineer"); newfun2(33, "engineer"); auto newfun3 = bind(globalFun2, "zack", placeholders::_2, 100, placeholders::_1); newfun3("coder", 33);
placeholders表示預留位置,_1表示新生成函數的第一個引數, _2表示新生成函數的第二個引數,將這些引數傳遞給原函數達到佔位的效果,原函數的其餘引數通過bind繫結固定值。
接下來定義類
class BindTestClass { public: BindTestClass(int num_, string name_) : num(num_), name(name_) {} static void StaticFun(const string &str, int age); void MemberFun(const string &job, int score); public: int num; string name; };
實現靜態函數和成員函數
void BindTestClass::StaticFun(const string &str, int age) { cout << "this is static function" << endl; cout << "name is " << str << endl; cout << "age is " << age << endl; } void BindTestClass::MemberFun(const string &job, int score) { cout << "this is member function" << endl; cout << "name is " << name << endl; cout << "age is " << num << endl; cout << "job is " << job << endl; cout << "score is " << score << endl; }
我們通過bind繫結靜態成員函數
//繫結類的靜態成員函數,加不加&都可以 // auto staticbind = bind(BindTestClass::StaticFun, placeholders::_1, 33); auto staticbind = bind(&BindTestClass::StaticFun, placeholders::_1, 33); staticbind("zack");
新生成的staticbind函數可以直接傳遞一個引數zack就完成了呼叫。接下來用bind繫結成員函數
BindTestClass bindTestClass(33, "zack"); // 繫結類的成員函數,一定要傳遞物件給bind的第二個引數,可以是類物件,也可以是類物件的指標 // 如果要修改類成員,必須傳遞類物件的指標 auto memberbind = bind(BindTestClass::MemberFun, &bindTestClass, placeholders::_1, placeholders::_2); memberbind("coder", 100); auto memberbind2 = bind(BindTestClass::MemberFun, placeholders::_3, placeholders::_1, placeholders::_2); memberbind2("coder", 100, &bindTestClass); //繫結類成員時,物件必須取地址 auto numbind = bind(&BindTestClass::num, placeholders::_1); std::cout << numbind(bindTestClass) << endl;
當然也可以直接用function物件接受bind返回的結果
// function接受bind返回的函數 function<void(int, string)> funcbind = bind(globalFun2, "zack", placeholders::_1, 100, placeholders::_2); funcbind(33, "engineer"); // function接受bind 成員函數 function<void(string, int)> funcbind2 = bind(BindTestClass::MemberFun, &bindTestClass, placeholders::_1, placeholders::_2); funcbind2("docker", 100); function<void(string, int, BindTestClass *)> funcbind3 = bind(BindTestClass::MemberFun, placeholders::_3, placeholders::_1, placeholders::_2); funcbind3("driver", 100, &bindTestClass); // function 直接接受成員函數,function的模板列表裡第一個引數是類物件參照 function<void(BindTestClass &, const string &, int)> functomem = BindTestClass::MemberFun; functomem(bindTestClass, "functomem", 88); // function 繫結類的靜態成員函數 function<void(const string &)> funbindstatic = bind(&BindTestClass::StaticFun, placeholders::_1, 33); funbindstatic("Rolis");
lambda和bind的使用就介紹到這裡
到此這篇關於C++超詳細梳理lambda和function的使用方法的文章就介紹到這了,更多相關C++ lambda和function內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45