1. 程式人生 > >C++11系列-lambda函式

C++11系列-lambda函式

原文地址:http://towriting.com/blog/2013/08/11/lambda-closures/

 C++11一個最激動人心的特性是支援建立lambda函式(有時稱為閉包)。這意味著什麼?一個Lambda函式是一個可以內聯寫在你程式碼中的函式(通常也會傳遞給另外的函式,類似於仿函式或函式指標)。使用Lambda,建立機動函式會更簡單,而以前你必須建立一個有名函式。在這篇文章中,我先用一些例子解釋為什麼lambda很酷,然後我會講解可能會用到的關於lambda的所有細節。

為什麼Lambda很酷

想象你有一個地址簿類,並且你想要提供一個可供檢索的函式。你可能會提供一個簡單的函式,接受一個字串然後返回滿足所有字串的地址。有時有些使用者可能希望這樣。不過假如他們只是想檢索域名或者檢索使用者名稱並且忽略域名結果;或者檢索出現在其他列表中的所有Email地址。這裡可能有許多可能的檢索方式。除了類中整合所有這些搜尋選項,提供一個通用的查詢方法,這個方法接受一個查詢規則的函式,這樣不是更好些嗎?讓我們叫這個函式findMatchingAddresses,它接受一個函式或仿函式物件。

#include <string>
#include <vector>
class AddressBook
{
    public:
    // 使用模板可以是我們忽略函式、仿函式和Lambda的不同
    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 )
{ // 呼叫傳遞到findMatchingAddresses的函式並檢測是否匹配規則 if ( func( *itr ) ) { results.push_back( *itr ); } } return results; } private: std::vector
<std::string> _addresses;
};

任何人可以傳遞一個包含地址查詢邏輯的函式給findMatchingAddresses。假如這個函式返回真,則得到相應的地址,地址將被返回。這種方式在以前的C++中一樣支援,不過卻遭遇一個致命缺陷:建立函式非常不方便。你必須先在其他地方定義好函式,你才能使用它。這就是Lambda出現的原因。

基本Lambda語法

在我們解決這個問題之前,讓我們看一下真實的lambda基本語法。

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

好,你找到lambda了嗎?它以[]開始。這個標識,叫做捕獲指定器,它告訴編譯器我們要建立一個lambda表示式。你將看到[](或者裡面有變數)在每一個lambda函式的開始。

接著,像其他函式一樣,我們需要一個引數列表:()。返回值呢?答案是我們不需要指定。在C++11中,假如編譯器可以推導lambda函式的返回值,它將幫你做這件事而不需你顯式指定。在這個例子裡,編譯器知道函式沒有返回值。我們只是有一個列印“hello world”的函式體。這一行事實上不會觸發關於列印的任何事:我們僅僅是建立了一個函式在這裡。基本上相當於定義了一個普通函式。

我們在下面一行呼叫了這個lambda函式:func(),像呼叫其它普通函式一樣。順便看到,配合auto做這些事情是多麼簡單!你不用擔心函式指標的醜陋語法。

在我們的例子中應用Lambda

讓我們看看怎樣將lambda應用到我們地址簿例子裡,首先我們建立一個查詢包含“.org”的email地址的簡單函式。

AddressBook global_address_book;
vector<string> findAddressesFromOrgs ()
{
    return global_address_book.findMatchingAddresses(
        // we're declaring a lambda here; the [] signals the start
        [] (const string& addr) { return addr.find( ".org" ) != string::npos; }
    );
}

再一次,我們以捕獲指示符[]開始,但這一次我們有一個引數:地址,並且我們檢測地址中是否含有“.org”。再一次說明,lambda的函式體並沒有在這裡執行;它只會在函式findMatchingAddresses內,當函式變數被使用時,lambda中的程式碼才會執行。換句話說,findMatchingAddresses的每個迴圈中會呼叫lambda函式,並傳給它一個地址作為引數,然後這個函式檢測地址是否包含“.org”。

變數捕獲

雖然這些簡單的lambda用法也不錯,但變數捕獲才是成就lambda卓越的祕方。假如你想建立一個查詢包含指定名字的短函式。如果可以寫出這樣的程式碼是不是非常不錯?

// read in the name from a user, which we want to search
string name;
cin>> name;
return global_address_book.findMatchingAddresses(
    // 注意lambda函式使用了變數 'name'
    [&] (const string& addr) { return addr.find( name ) != string::npos; }
);

可以證明示例程式碼是合法的,並且它展現了lambda函式的價值。我們可以獲取宣告在lambda函式之外的變數(name),並在lambda之內使用。當findMatchingAddresses呼叫我們的lambda函式,函式體會被執行,當addr.find被呼叫,它處理使用者程式碼傳進的name。為了使這可以執行的唯一要做的事是捕獲變數。我用[&]捕獲指示做這件事,而不是用[]。[]是告訴編譯器不捕獲任何變數,而[&]是告訴編譯器去捕獲變數。

是不是不可思議?我們建立了一個簡單的可以捕獲變數的函式,並將它傳給find函式,所有這些只用了幾行程式碼。如果不用C++11實現這些,我們需要建立一個仿函式或者給AddressBook類新增一個特殊方法。用C++11,我們可以輕易實現一個簡單的介面函式,但支援各種檢索的功能。

只是好玩,我們想查詢email地址小於某個特殊長度的地址。我們可以再一次輕鬆實現:

int min_len = 0;
cin >> min_len;
return global_address_book.find( [&] (const string& addr) { return addr
            
           

相關推薦

C++11系列-lambda函式

原文地址:http://towriting.com/blog/2013/08/11/lambda-closures/  C++11一個最激動人心的特性是支援建立lambda函式(有時稱為閉包)。這意味著什麼?一個Lambda函式是一個可以內聯寫在你程式碼

c++11lambda表示式與傳統的函式指標

#include <iostream> using namespace std; #include <functional> //std::function 標頭檔案 //傳統的函式指標 typedef int(*fun0)(int n); int

C++11系列——函式物件(Function Object)

之前總結過一篇Boost之高階函式——函式物件,介紹了幾個用於處理函式物件的 Boost C++ 庫。而目前C++11的標準庫std已經提供了函式物件的一些功能。 In mathematics and computer science, a high

C++11系列-什麽是C++11

證明 需要 特性 泛型 枚舉 聲明 繼續 特征 線程 什麽是C++0x? C++0x是C++最新標準標準化過程中的曾用名,在這一系列文章中我們將介紹最新標準添加的一系列新的語言特性。在2011年9月份,C++0x正式由官方發布並命名C++11,現在很多編譯器已經支持了部分

C++11Lambda表示式

    C++11的一大亮點就是引入了Lambda表示式。利用Lambda表示式,可以方便的定義和建立匿名函式。對於C++這門語言來說來說,“Lambda表示式”或“匿名函式”這些概念聽起來好像很深奧,但很多高階語言在很早以前就已經提供了Lambda表示式的功能,如C#,Pyth

C++11 移動建構函式

文章目錄 一、引言 二、左值和右值 三、深拷貝建構函式 四、右值引用 五、移動建構函式 六、std::move() 七、參考資料 一、引言 移動建構函式是什麼?先舉個例子,你有一本書,你不想看,但我很想看,那麼我

c++11 繼承建構函式

若基類擁有數量眾多的不同版本的建構函式,而派生類中只有一些成員函式,則對於派生類而言,其建構函式就等同於構造基類。 struct A { A(int i) {} A(double d, int i) {} A(float f, int i, const char* c) {} //... };

C++11--移動建構函式

【知識點梳理】1、預設建構函式為淺拷貝2、左值和右值3、右值引用優化效能,避免深拷貝4、移動建構函式【正文】class A_2 { public: A_2() :m_ptr(new int(0)) { } ~A_2() { delete m_ptr; }

C++11: 使用 lambda 建立模板類 的 物件

C++ 中 lambda 可以直接傳遞給模板函式如 std::sort, 但無法傳給模板類如 std::map,但是,使用一點小技巧,可以使用 lambda 建立模板類的物件,省了很多麻煩的 coding。這裡給出一個示例: #include <stdio.h>

C++11系列學習之三----array/valarray

建立陣列,是程式設計中必不可少的一環。我們一般可以有以下幾種方法來建立陣列。 一、C++內建陣列 陣列大小固定,速度較快 通用格式是:資料型別   陣列名[ 陣列大小 ]; 如 int a[40];//一維陣列   int a[5][10];//二維陣列 二、

c++11呼叫成員函式mem_fn和適合普通函式指標

在C++11之前,呼叫一個成員函式指標做為容器的回撥演算法時,可以根據其容器記憶體儲的內容是物件還是指標呼叫相關的mem_fun和_mem_fun_ref函式來與演算法等進行適配,搭配使用。 在c++11中加入mem_fn來對成員函式的呼叫進行相關的封裝,不過也需要對方法

c++ 11 陣列 和lambda表示式 語法 / 函式包裝器 基本用法

//倒敘遍歷陣列並輸出  // []裡面的變數可以當做返回值來理解 (int x) 這裡就是每次迭代器的值,也就是陣列的元素的值 void main() { array<int, 5>

C++11 Lambda表示式(匿名函式

C++11引入了lambda表示式,使得程式設計師可以定義匿名函式,該函式是一次性執行的,既方便了程式設計,又能防止別人的訪問。 Lambda表示式的語法通過下圖來介紹:           

C++11 lambda表示式與函式物件

C++ lambda表示式與函式物件 lambda表示式是C++11中引入的一項新技術,利用lambda表示式可以編寫內嵌的匿名函式,用以替換獨立函式或者函式物件,並且使程式碼更可讀。但是從本質上來講,lambda表示式只是一種語法糖,因為所有其能完成的工作都可以用其它

C++11新特性:Lambda函式(匿名函式

基本的Lambda函式 我們可以這樣定義一個Lambda函式: #include <iostream> using namespace std; int main() { auto func = [] () { c

C++11新特性之Lambda函式

我是搞C++的 一直都在提醒自己,我是搞C++的;但是當C++11出來這麼長時間了,我卻沒有跟著隊伍走,發現很對不起自己的身份,也還好,發現自己也有段時間沒有寫C++程式碼了。今天看到了C++中的Lambda表示式,雖然用過C#的,但是C++的,一直沒有用,也不知道怎麼

C++11 Lambda函式(匿名函式

 C++11引入了lambda表示式,使得程式設計師可以定義匿名函式,該函式是一次性執行的,既方便了程式設計,又能防止別人的訪問。 Lambda表示式的語法通過下圖來介紹: Lambda表示

C++11 lambda 表達式解析

bar ... 以及 cal lam c++ iostream 沒有 red C++11 新增了很多特性,lambda 表達式是其中之一,如果你想了解的 C++11 完整特性,建議去這裏,這裏,這裏,還有這裏看看。本文作為 5 月的最後一篇博客,將介紹 C++11 的 la

C++11 並發指南系列(轉)

flag target ise shared 編程 mutex 指南 sha targe 本系列文章主要介紹 C++11 並發編程,計劃分為 9 章介紹 C++11 的並發和多線程編程,分別如下: C++11 並發指南一(C++11 多線程初探)(本章計劃 1-2 篇,已完

C++11 Lambda表達式(匿名函數)

class 訪問 namespace 表達式 span sin clas style col http://www.cnblogs.com/RainyBear/p/5733399.html 匿名函數,好屌的樣子。 Lambda表達式的引入標誌,在‘[]’裏面可以填入‘=’