論C++的lambda是函數(shù)還是對(duì)象
先說(shuō)結(jié)論:
- 對(duì)于有捕獲的
lambda
,其等價(jià)于對(duì)象。 - 對(duì)于沒(méi)有任何捕獲的
lambda
,其等價(jià)于函數(shù)!
首先,很多C++程序員從lambda
用法上反推容易發(fā)現(xiàn)是對(duì)象,因?yàn)閘ambda可以捕獲!這是函數(shù)做不到的。的確,比如:
int n = 100; auto foo = [n](int a) { ? ? return a > n; }; cout<< foo(99);
如果編譯器要實(shí)現(xiàn)foo
,大致類比這種寫(xiě)法(可能真實(shí)的實(shí)現(xiàn)細(xì)節(jié)不是這樣,但思路類似)∶
struct Foo { ? ? Foo(int i) {n=i;} ? ? bool operator()(int a) { ? ? ? ? return a > n; ? ? } private: ? ? int n; }; ... int n = 100; Foo foo(n); cout<< foo(99);
如果是引用捕獲了變量,那么struct內(nèi)有一個(gè)指針成員持有被引用捕獲的變量的地址。
比如:
set<int> ns = {100, 200, 300}; auto foo = [&ns](int a) { ? ? return ns.find(a); }; cout<< foo(99);
大致等價(jià)于:
struct Foo { ? ? Foo(set<int>* p) {p_ns = p;} ? ? bool operator()(int a) { ? ? ? ? auto &ns = *p-ns; ? ? ? ? return ns.find(a); ? ? } private: ? ? set<int>* p_ns; }; ... set<int> ns = {100, 200, 300}; Foo foo(&ns); cout<< foo(99);
然而……這并不是全部!
在沒(méi)有捕獲任何東西的時(shí)候,lambda
其實(shí)是等價(jià)于普通的函數(shù)的!可以用Linux C中函數(shù)pthread_create()來(lái)驗(yàn)證!它只能接收一個(gè)參數(shù)是void*,返回值也是void*的回調(diào)函數(shù)。
神奇的是,無(wú)參的lambda
也可以被pthread_create()
使用!
using namespace std; struct A { ? ? void* operator()(void*) { ? ? ? ? cout<<"xxxx"<<endl; ? ? ? ? return nullptr; ? ? } }; int main() { ? ? A a; ? ? a(NULL); ? ? pthread_t t; ? ? //pthread_create(&t, NULL, a, NULL); // 編譯失敗 ? ? auto cb = [](void*)->void* { ? ? ? ? cout<<"xxxx"<<endl; ? ? ? ? return nullptr; ? ? }; ? ? pthread_create(&t, NULL, cb, NULL); // 編譯通過(guò) ? ? pthread_join(t, NULL); ? ? return 0; }
上面代碼還可以再改一下,讓cb去捕獲一個(gè)變量, 比如:
auto cb = [&](void*)->void* { ? ? ? ? cout<<"xxxx"<<endl; ? ? ? ? return nullptr; ? ? }; ? ? pthread_create(&t, NULL, cb, NULL);
這時(shí),給pthread_create()傳入cb同樣會(huì)編譯失??!錯(cuò)誤信息:
cb.cpp: In function ‘int main()': cb.cpp:23:30: error: cannot convert ‘main()::<lambda(void*)>' to ‘void* (*)(void*)' ? ?23 | ? ? pthread_create(&t, NULL, cb, NULL); ? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^~ ? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| ? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?main()::<lambda(void*)> In file included from /usr/include/x86_64-linux-gnu/c++/9/bits/gthr-default.h:35, ? ? ? ? ? ? ? ? ?from /usr/include/x86_64-linux-gnu/c++/9/bits/gthr.h:148, ? ? ? ? ? ? ? ? ?from /usr/include/c++/9/ext/atomicity.h:35, ? ? ? ? ? ? ? ? ?from /usr/include/c++/9/bits/ios_base.h:39, ? ? ? ? ? ? ? ? ?from /usr/include/c++/9/ios:42, ? ? ? ? ? ? ? ? ?from /usr/include/c++/9/ostream:38, ? ? ? ? ? ? ? ? ?from /usr/include/c++/9/iostream:39, ? ? ? ? ? ? ? ? ?from cb.cpp:1: /usr/include/pthread.h:200:15: note: ? initializing argument 3 of ‘int pthread_create(pthread_t*, const pthread_attr_t*, void* (*)(void*), void*)' ? 200 | ? ? ? void *(*__start_routine) (void *), ? ? ? | ? ? ? ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
這其實(shí)也不難理解,C++在lambda的設(shè)計(jì)上也貫徹著零開(kāi)銷 (Zero Overhead)原則,也就是C++不在性能上干多余的事,顯然函數(shù)比對(duì)象開(kāi)銷更小。所以即使同為lambda,在有無(wú)捕獲的時(shí)候,其底層實(shí)現(xiàn)其實(shí)是截然不同的!
到此這篇關(guān)于論C++的lambda是函數(shù)還是對(duì)象的文章就介紹到這了,更多相關(guān)C++中的lambda內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言基礎(chǔ)隱式類型轉(zhuǎn)換與強(qiáng)制類型轉(zhuǎn)換示例解析
最接地氣的有關(guān)類型轉(zhuǎn)換的介紹,此處對(duì)于類型轉(zhuǎn)換的相關(guān)知識(shí)點(diǎn)做一些簡(jiǎn)要的介紹,作者實(shí)屬初學(xué),難免文章中有內(nèi)容理解不到位或者有不當(dāng)之處,還請(qǐng)朋友們不吝指正,希望大家多多給予支持2021-11-11C語(yǔ)言學(xué)生學(xué)籍管理系統(tǒng)課程設(shè)計(jì)
這篇文章主要介紹了C語(yǔ)言學(xué)生學(xué)籍管理系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01