「C++11」Lambda 表達式

 a lambda維基百科上面對於 lambda 的引入是以下描述的:html

在標準 C++,特別是當使用 C++ 標準程序庫算法函數諸如 sort 和 find。用戶常常但願可以在算法函數調用的附近定義一個臨時的述部函數(又稱謂詞函數,predicate function)。因爲語言自己容許在函數內部定義類型,能夠考慮使用函數對象,然而這一般既麻煩又冗贅,也阻礙了代碼的流程。此外,標準 C++ 不容許定義於函數內部的類型被用於模板,因此前述的做法是不可行的。C++11 對lambda的支持能夠解決上述問題。ios

lambda 表達式的簡單語法以下:[capture] (parameters) -> return value { body }c++

一、最簡單的例子:算法

#include <iostream> using namespace std; int main() { auto func = [] () { cout << "Hello world"; }; func(); }

上面的 lambda 表達式 func 沒有傳入任何參數,也沒有返回值,甚至咱們能夠對其簡寫成:auto func = [] { cout << "Hello world"; } 。而且配合 C++11標準加入的 auto 自動類型判斷,省去了之前定義函數指針冗雜繁瑣的過程,程序看上去如何優雅、簡潔。shell

二、更加深刻的示範:編程

假設咱們有一個存放書籍地址的類,須要傳入一個「搜索知足條件地址」的函數,而且將類定義成以下模樣:閉包

class AddressBook
{
public:
    template<typename Func>
    std::vector<std::string> findMatchingAddresses (Func func)
    { 
        std::vector<std::string> results;
        for ( auto itr = _addresses.begin(), end = _addresses.end(); itr != end; ++itr )
        {    
            if ( func( *itr ) )
            {
                results.push_back( *itr );
            }
        }
        return results;
    }
private:
    std::vector<std::string> _addresses;
};

類 AddressBook 封裝了 findMatchingAddresses 函數,返回知足咱們須要的書目,下面咱們看看 lambda 表達式如何實現這一過程:函數

AddressBook global_address_book;
vector<string> findAddressesFromOrgs ()
{
    return global_address_book.findMatchingAddresses( 
        [] (const string& addr) { return addr.find( ".org" ) != string::npos; } 
    );
}

上面函數返回知足地址中帶有 ".org" 字樣的書籍條目,lambda 表達式雖然沒有定義返回類型,可是編譯器能夠根據咱們的 return 語句自動判斷返回值是 boolean 類型。咱們的 lambda 表達式中 [] 並無 capture 任何變量,再下面的例子中將展現 [&] :oop

string name;
cin >> name;
return global_address_book.findMatchingAddresses( 
    [&] (const string& addr) { return addr.find( name ) != string::npos; } 
);

再次注意到,類 global_address_book 居然可以訪問到咱們定義的局部變量 name 字符串,這正是 lambda 表達式的強大之處,[&] 表明 lambda body 中用到的變量都以「reference」的方式使用,還有更多的 capture 用法這裏就再也不敘述,有興趣進一步瞭解的同窗能夠自行搜索。性能

三、Lambda 表達式使 STL 更增強大:

傳統的狀況下,咱們會用下面的方式去訪問容器裏面的數據:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
//...
for ( auto itr = v.begin(), end = v.end(); itr != end; itr++ )
{
    cout << *itr;
}

可是當咱們有了 Lambda 以後,利用 STL 裏面的 for_each ,將會變成下面的代碼:

vector<int> v;
v.push_back( 1 );
v.push_back( 2 );
//...
for_each( v.begin(), v.end(), [] (int val)
{
    cout << val;
});

你可能會想,上面的 for_each 循環,會不會使咱們的程序有性能上的損耗?答案是否認的:for_each 的效率和迭代的效率是一致的,甚至加上 Lambda 以後,for_each 會利用 "loop unrolling" 機制使程序運行的更快。

Lambda 的引入給咱們帶來了一種全新的編程體驗,它可讓咱們把 "function" 當作是 "data" 同樣傳遞,而且使咱們從繁瑣的語法中解放出來,更加關注於 "算法" 自己。咱們也稱 Lambda 爲 Closure(閉包),顧名思義,這使咱們的函數變得更加私有,因此限制了別人的訪問,同時咱們也能夠更加方便的編程。

四、Lambda 與 資源管理:

前面在個人 「理解智能指針」一文中提到,智能指針能夠利用 C++ 的 RAII(Resource acquisition is initialization) 特性,在類型(class)的析構函數時來完成自動釋放指針所指向對象的目的。一樣,在 Lambda 中,又把 RAII 這一特性體現的淋漓盡致:

class ScopeGuard
{
public:
    explicit ScopeGuard(std::function<void()> onExitScope)
        : onExitScope_(onExitScope)
    { }
    ~ScopeGuard()
    {
            onExitScope_();
    }
private:
    std::function<void()> onExitScope_;
private: // noncopyable
    ScopeGuard(ScopeGuard const&);
    ScopeGuard& operator=(ScopeGuard const&);
};
int main() {
 HANDLE h = CreateFile(...); ScopeGuard onExit([&] { CloseHandle(h); });
    ...
return 0;
}

看到上面的代碼,我已經被 C++11 引入 Lambda 以後所帶來的強大功能所折服了。咱們沒必要擔憂什麼時候去釋放資源,而且連釋放資源的方式「如 CloseHandle(h)」也與咱們的代碼緊密的融合在了一塊兒,這將是十分美妙的一件事情。

五、Lambda 究竟是什麼類型:

auto func = [] () { cout << "hello world"; };
std::function<void ()> func = [] () { cout << "hello world"; };

auto func = [] (int val) { cout << val; return false; };
std::function<bool (int)> func = [] (int val) { cout << val; return false; };

 上面的上下 2 行代碼效果是等效的,看到這裏是否有種似曾相識的感受?那 Lambda 和 咱們定義的函數指針有什麼區別呢:

typedef int (*func)();
func f = [] () -> int { return 2; };
f();

沒錯,這段代碼是能夠正常運行的,由於 Lambda 表達式中並無 capture 任何本地變量,所以會被編譯成普通的函數指針。最後採用 coolshell 裏面 Lambda 的 2 點總結: 1)能夠定義匿名函數,2)編譯器會把其轉成函數對象。 

六、 使用 Lambda 進行代碼委託(調用):

 

「參考資料」

http://zh.wikipedia.org/wiki/C%2B%2B11

http://mindhacks.cn/2012/08/27/modern-cpp-practices/

http://www.cprogramming.com/c++11/c++11-lambda-closures.html

http://coolshell.cn/articles/5265.html

相關文章
相關標籤/搜索