論C++的lambda是函數(shù)還是對象
先說結論:
- 對于有捕獲的
lambda,其等價于對象。 - 對于沒有任何捕獲的
lambda,其等價于函數(shù)!
首先,很多C++程序員從lambda 用法上反推容易發(fā)現(xiàn)是對象,因為lambda可以捕獲!這是函數(shù)做不到的。的確,比如:
int n = 100;
auto foo = [n](int a) {
? ? return a > n;
};
cout<< foo(99);如果編譯器要實現(xiàn)foo,大致類比這種寫法(可能真實的實現(xiàn)細節(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內有一個指針成員持有被引用捕獲的變量的地址。
比如:
set<int> ns = {100, 200, 300};
auto foo = [&ns](int a) {
? ? return ns.find(a);
};
cout<< foo(99);大致等價于:
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);然而……這并不是全部!
在沒有捕獲任何東西的時候,lambda其實是等價于普通的函數(shù)的!可以用Linux C中函數(shù)pthread_create()來驗證!它只能接收一個參數(shù)是void*,返回值也是void*的回調函數(shù)。
神奇的是,無參的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); // 編譯通過
? ? pthread_join(t, NULL);
? ? return 0;
}上面代碼還可以再改一下,讓cb去捕獲一個變量, 比如:
auto cb = [&](void*)->void* {
? ? ? ? cout<<"xxxx"<<endl;
? ? ? ? return nullptr;
? ? };
? ? pthread_create(&t, NULL, cb, NULL);這時,給pthread_create()傳入cb同樣會編譯失??!錯誤信息:
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 *), ? ? ? | ? ? ? ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
這其實也不難理解,C++在lambda的設計上也貫徹著零開銷 (Zero Overhead)原則,也就是C++不在性能上干多余的事,顯然函數(shù)比對象開銷更小。所以即使同為lambda,在有無捕獲的時候,其底層實現(xiàn)其實是截然不同的!
到此這篇關于論C++的lambda是函數(shù)還是對象的文章就介紹到這了,更多相關C++中的lambda內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
關于函數(shù)調用方式__stdcall和__cdecl詳解
下面小編就為大家?guī)硪黄P于函數(shù)調用方式__stdcall和__cdecl詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-09-09

