日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++11语言新特性-《C++标准库(第二版)》读书笔记

發(fā)布時間:2025/4/5 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++11语言新特性-《C++标准库(第二版)》读书笔记 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

      • 3.1.1 微小但重要的語法提升
        • Template 表達式內(nèi)的空格
        • nullptr 和std::nullptr_t
      • 3.1.2 以auto 完成自動類型推導(dǎo)
      • 3.1.3 一致性初始化(Uniform Initialization) 與初值列(Initializer List)
      • 3.1.4 Range-Based for 循環(huán)
      • 3.1.5 Move 語義和Rvalue Reference
        • Rvalue和Lvalue Reference 的重載規(guī)則
        • 返回Rvalue Reference
      • 3.1.6 新式的字符串字面常量(String Literal)
        • Raw String Literal
      • 3.1.7 關(guān)鍵字noexcept
      • 3.1.8 關(guān)鍵字constexpr
      • 3.1.9 嶄新的Template 特性
        • Variadic Template
        • Alias Template(帶別名的模板,或者叫Template Typedef)
        • 其他的Template新特性
      • 3.1.10 Lambda
        • Lambda的語法
        • Capture(用以訪問外部作用域)

3.1.1 微小但重要的語法提升

Template 表達式內(nèi)的空格

“在兩個template表達式的閉符之間放一個空格” 的要求已經(jīng)過時了

vector<list<int> >; //OK in each C++ version vector<list<int>>; // OK since C++11

上述兩種形式都可以現(xiàn)在。

nullptr 和std::nullptr_t

C++11允許使用nullptr取代0或者NULL,用來表示一個pointer(指針)指向所謂的 no value (此不同于擁有一個不確定值) 。 這個新特性能幫助我們在“null pointer被解釋為一個整數(shù)值” 時避免誤解。

例如

void f(int); void f(void *);f(0); // calls f(int) f(NULL); // calls f(int) if NULL is 0 ,ambiguous otherwisef(nullptr); // calls f(void*)

nullptr 是新關(guān)鍵字。它被自動轉(zhuǎn)換為各種pointer類型,但不會被轉(zhuǎn)換為任何整數(shù)類型。 它擁有類型std::nullptr_t ,定義于< cstddef>, 所以現(xiàn)在甚至可以重載函數(shù)令它們接受 null pinter. 注意, std:: nullptr_t 被視為一個基礎(chǔ)類型。

3.1.2 以auto 完成自動類型推導(dǎo)

C++11 允許聲明一個變量或?qū)ο?#xff08;Object)而不需要指明其類型,只需要說它是auto 。例如

auto i =42; // i has type intdouble f(); // auto d=f(); // d has type double

以auto聲明的變臉,其類型會根據(jù)其初值被自動推導(dǎo)出來,因此一定需要一個初始化操作:

auto i; //ERROR : can't deduce the type of i

可為它加上額外的限定符,例如

static auto vat =0.19;

如果類型很長或表達式很復(fù)雜,auto特別有用,例如

vector<stirng> v;auto pos = v.begin(); // pos has type vector<string> :: iteratorauto l = [] (int x) -> bool { // l has the type of a lambda..., //taking an int and returning a bool };

上述末尾那個奇怪的東西是個對象,表示一個lambda。

3.1.3 一致性初始化(Uniform Initialization) 與初值列(Initializer List)

C++11引入了“一致性初始化(uniform initialization)”的概念, 意思是面對任何初始化動作,你可以使用相同語法,也就是使用大括號。以下皆成立:

int values [] {1,2,3}; std::vector<int> v{2,3,5,7,11,13,17};std::vector<std::string> cities{"Berlin","New York","London","Braunschweig","Cairo","Cologne" };std::complex<double> c{4.0, 3.0 }; //equivalent to c(4.0 , 3.0)

初始列(initializer list) 會強迫造成所謂value initializaiton ,意思是即使某個local 變量屬于某種基礎(chǔ)類型(那通常是不明確的初值)也會被初始化為0(或者nullptr----如果它是個pointer的話):

int i // i has undefined value int j{}; // j is initialized by 0int* p; // p has undefined value int* q{}; // q is initialized by nullptr

然而請注意,窄化(narrowing) -----也就是精度降低或造成數(shù)值變動----- 對大括號而言是不可成立的。例如:

int x1(5.3) ; // OK,but OUCH:x1 becomes 5 int x2 =5.3; // OK,but OUCH: x2 becomes 5int x3{5.0}; //ERROR:narrowing int x4={5.3}; //ERROR :narrowingchar c1{7}; //OK:even though 7 is an int , this is not narrowingchar c2{99999};// ERROR:narrowing(if 99999 doesn't fit into a char)std::vector<int> v1{1,2,4,5}; //OKstd::vector<int> v2{1,2.3, 4, 5.6}; // ERROR:narrowing doubles to ints

為了支持“用戶自定義類型之初值列”的概念, C++11提供了class template std:: initializer_list<>,用來支持以一系列值(a list if values) 進行初始化,或在“你想要處理一系列值(a list of values)” 的任何地點進行初始化,例如:

void print( std::initializer_list<int> vals){for(auto p=vals.begin(); p!=vals.end();++p)std::cout<< *p <<<<endl; }print({ 12, 3, 5, 7, 11, 13, 15}); //pass a list of values to print()

當(dāng)“指明實參個數(shù)” 和“指明一個初值列” 的構(gòu)造函數(shù)(ctor)同時存在,嗲有初值列的那個版本勝出:

class P {public:P(int ,int );P(std:: initialier_list<int>); };P p(77, 5); //calls P::P(int,int )P q{77 , 5}; // calls P::P (intializer_list)P r{77,5,42};//calls P::P (intializer_list)P s={77,5};//calls P::P (intializer_list)

如果上述“帶有1個初值列”的構(gòu)造函數(shù)不存在,那么接受2個int的那個構(gòu)造函數(shù)會被調(diào)用以初始化q和s,而r的初始化將無效。

由于初值列的關(guān)系,explicit之于“接受一個以上實參”的構(gòu)造函數(shù)也會變得不一樣。如今你可以令“多數(shù)值自動類型轉(zhuǎn)換”不再起作用,即使初始化以=語法進行:

class P{public:P(int a,int b){...}explicit P(int a,int b,int c){...}};P x(77 , 5); //OK P y{77,5};//OK P z {77,5,42}; //OK P v={77,5};//OK(implicit type conversion allowed) P w={77,5,42};// ERROR due to explicit(no implicit type conversion allowed)

同樣地,explicit構(gòu)造函數(shù)如果接受的是個初值列,會失去“初值列帶有0個、1個或多個初值”的隱式轉(zhuǎn)換能力。

void fp(const P&);fp({47,11});//OK,implicit conversion of{47,11} into P fp({47,11,3});//ERROR due to explicit fp(P{47,11});//OK,explicit conversion of {47,11}into P fp(P{47,11,3}); //OK,explicit conversion of {47,11,3} into P

3.1.4 Range-Based for 循環(huán)

C++11 引入了一種嶄新的for循環(huán)形式,可以逐一迭代某個給定的區(qū)間、數(shù)組、集合(range,array,or collection)內(nèi)的每一個元素。 其他編程語言可能稱此為foreach循環(huán)。其一般性語法如下:

for(decl:coll){statement }

其中decl是給定的coll集合的每個元素的聲明;針對這些元素,給定的statement會被執(zhí)行。例如下面針對傳入的初值列的每個元素,調(diào)用給定的語句,于是在標(biāo)準(zhǔn)輸出裝置cout輸出元素值:

for( int i: {2,3,5,7,9,11,13,15}){std::cout<<i <<std::endl; }

如果要將vector vec的每個元素elem乘以3,可以這么做:

std::vector<double> vec; ... for( auto & elem: vec){elem*=3; }

這里“聲明elem為一個reference”很重要,若不這樣做,for循環(huán)中的語句會作用在元素的一份local copy身上。

這意味著,為了避免調(diào)用每個元素的copy構(gòu)造函數(shù)和析構(gòu)函數(shù),你通常應(yīng)該聲明當(dāng)前元素為一個const reference。于是一個用來“打印某集合內(nèi)所有元素”的泛型函數(shù)應(yīng)該寫成這樣

template<typename T> void printElements(const T& coll){for(const auto& elem:coll){std::cout<<elem<<std::endl;} }

在這里,這種所謂range-based for 語句等同于:

{for(auto _pos=coll.begin(); _pos != coll.end(); ++_pos){const auto &elem =*_pos;std::cout<<elem<< std::endl;} }

一般而言,如果coll提供成員函數(shù)begin()和end(),那么一個range-based for 循環(huán)聲明為

for (decl: coll){statement }

便等同于:

for( auto _pos=coll.begin(),_end=coll.end(); _pos!=_end; ++_pos){decl= *_pos;statement }

或者如果不滿足上述條件,那么也等同于一下使用一個全局性begin()和end()且兩者都接受coll為實參:

{for(auto _pos=begin(coll),_end=end(coll); _pos!=_end;++_pos){decl=*_pos;statement}}

于是,你甚至可以針對初值列(initializer list)使用range-based for循環(huán),因為class template std::initializer_list<>提供了成員函數(shù)begin()和end().

此外還有一條規(guī)則,允許你使用尋常的、大小已知的C-style array,例如:

int array[]={1, 2, 3, 4, 5};long sum=0; //process sum of all elementsfor(int x:array)sum+=x;for(auto elem: {sum,sum*2, sum*4})std::cout<< elem <<std::endl;

產(chǎn)生如下輸出:

當(dāng)元素在for循環(huán)中被初始化為decl,不得有任何顯式類型轉(zhuǎn)換(explicit type conversion) 。因此下面的代碼無法通過編譯:

class C{public:explicit C(const std::string& s);// explicit(!) type conversion from strings };std::vector<std::string> vs; for(const C& elem:vs){ // ERROR,no conversion from string to C definedstd::cout<<elem<<std::endl; }

3.1.5 Move 語義和Rvalue Reference

C++11的一個最重要的特性就是,支持move semantic(搬遷語義)。這項特性更進一步進入了C++11主要設(shè)計目標(biāo)內(nèi),用以避免非必要拷貝(copy)和臨時對象(temporary)。

這項新特性十分復(fù)雜,這里盡量給出一份簡明扼要的介紹和摘要。

考慮以下代碼

void createAndInsert(std::set<X>& coll){X x;// create an object of type Xcoll.insert(x); //insert it into the passed collection}

在這里我們將新對象插入集合(collection)中,后者提供了一個成員函數(shù)可為傳入的元素建立一份內(nèi)部拷貝(internal copy):

namespace std{template<typeneme T,..> class set{public:...insert(const T &v);// copy value of v}; }

這樣的行為是有用的,因為集合(collection)提供value semantic 及安插“臨時對象”(temporary object) 或“安插后會被使用或被改動的對象”的能力:

X x; coll.insert(x); //inserts copy of xcoll.insert(x+x); //inserts copy of temporary rvaluecoll.insert(x); //insert copy of x (although x is not used any longer)

然而,對于后兩次x安插動作,更好的是指出“被傳入值(也就是x+x 的和以及x)不再被調(diào)用者使用”,如此一來coll內(nèi)部就不需為它建立一份copy且“以某種方式move其內(nèi)容進入新建元素中”。當(dāng)x的復(fù)制成本高昂的時候—例如它是個巨大的string集合—這會帶來巨大的效能提升。

自C++11開始,上述行為成為可能,然而程序員必須自行指明“move是可行的,除非被安插的那個臨時對象還會被使用”。雖然編譯器自身也有可能找出這個情況,允許程序員執(zhí)行這項工作畢竟可使這個特性被用于邏輯上任何適當(dāng)之處。先前的代碼只需要簡單改成這樣:

X x; coll.insert(x); //inserts copy of x(OK,x is still used)coll.insert(x+x); //moves(or copies) contents of temporary rvaluecoll.insert(std::move(x)); //moves(or copies) contents of x into coll

有了聲明于< utility >的std::move() ,x可被moved而不再被copied 。然而,std::move() 自身并不做任何moving工作,它只是將其實參轉(zhuǎn)成一個所謂的rvalue reference ,那是一種被聲明為 X&&的類型。 這種新類型主張rvalue(不具名的臨時對象只能出現(xiàn)在賦值操作的右側(cè))可被改動內(nèi)容。 這份契約的含義是:這是個不再被需要的(臨時)對象,所以你可以“偷”其內(nèi)容和/或其資源。

現(xiàn)在,我們讓集合提供一個insert()重載版本,用以處理這些rvalue reference:

namespace std{template<typename T,...> class set{public:...insert(const T& x); //for lvalues:copies the value...insert(T &&x); // for rvalues:moves the value...};}

我們可以優(yōu)化這個針對rvalue reference 的重載版本,令它“偷取”x的內(nèi)容。 為了這么做,需要type of x的幫助,因為只有type of x 擁有接近本質(zhì)的機會和權(quán)利。 舉個例子,你可以運用internal array 和pointer of x 來初始化被安插的元素。如果class x 本身是個復(fù)雜類型,原本你必須為它逐一復(fù)制元素,現(xiàn)在這么做則會帶來巨大的效能改善。欲初始化新的內(nèi)部元素,我們只需調(diào)用class X提供的一個所謂move構(gòu)造函數(shù),它“偷取”傳入的實參值,初始化一個新元素。所有復(fù)雜類型都應(yīng)該提供這樣一個特殊構(gòu)造函數(shù) ----C++標(biāo)準(zhǔn)庫也提供了-----永安里將一個既有元素的內(nèi)容搬遷(move)到新元素中:

class X{public:X(const X& lvalue); //copy constructorX(X&& rvalue); //move constructor}

舉個例子,string 的move構(gòu)造函數(shù)只是將既有的內(nèi)部字符數(shù)組(existing internal character array )賦予(assign)新對象,而非建立一個新arrry然后復(fù)制所有元素。 同樣情況也適用于所有集合class:不再為所有元素建立一份拷貝,只需將內(nèi)部內(nèi)存(internal memory)賦予新對象就行。如果move構(gòu)造函數(shù)不存在,copy構(gòu)造函數(shù)就會被用上。

零位,你必須確保對于被傳對象(其value被"偷取")的任何改動—特別是析構(gòu)----都不至于沖擊新對象(如今擁有value)的狀態(tài)。因此,你往往必須清除被傳入的實參的內(nèi)容,例如將nullptr賦值給“指向了容器元素”的成員函數(shù)。

將“move semantic 被調(diào)用”的對象的內(nèi)容清除掉,嚴(yán)格來說并非必要,但不這樣做的話會造成整個機制幾乎失去用途。事實上,一般而言,C++標(biāo)準(zhǔn)庫的class保證了,在一次move之后,對象處于有效但不確定的狀態(tài)。也就是說,你可以在move之后對它賦予新值,但當(dāng)前值是不確定的。STL容器則保證了,被搬移內(nèi)容者,搬移后其值為空。

同樣地,任何nontrivial class都該同時提供一個copy assignment和一個move assignment 操作符:

class X{public:X& operator=(const X& lvalue); //copy assignment operatorX& operator=(X&& rvalue); // move assignment operator};

對于string和集合,上述操作符可以簡單交換(swapping)內(nèi)部內(nèi)容和資源就好。然而你也應(yīng)該清除*this 的內(nèi)容,因為這個對象可能持有資源(如lock),因而最好很快釋放它們。 再強調(diào)一次,move semantic 并不要求你那么做,但這是C++標(biāo)準(zhǔn)庫容器所提供的一種優(yōu)越質(zhì)量。

最后,請注意兩個相關(guān)議題:1)rvalue和lvalue reference 的重載規(guī)則;2)返回rvalue reference.

Rvalue和Lvalue Reference 的重載規(guī)則

Rvalue和lvalue的重載規(guī)則(overloading rule)如下:
如果你只實現(xiàn) void foo(X&);而沒有實現(xiàn)void foo(X&&); 行為如同C++98:foo() 可以lvalue但不能因rvalue被調(diào)用。

如果你實現(xiàn)void foo(const X&); 而沒有實現(xiàn)void foo(X&&); 行為如同C++98:foo()可以lvalue也可因rvalue被調(diào)用。

如果你實現(xiàn)void foo(X&); void foo(X&&); 或void foo(const X&); void foo(X&&); 你可以區(qū)分“為rvalue服務(wù)”和“為lvalue服務(wù)”.為“rvalue服務(wù)”的版本被允許且應(yīng)該提供move語義。也就是說,它可以“偷取”實參的內(nèi)部狀態(tài)和資源。

如果你實現(xiàn)void foo(X&&); 但既沒有實現(xiàn) void foo(X&);也沒有實現(xiàn)void foo(const X&); ,foo()可因rvalue被調(diào)用,但當(dāng)你嘗試以lvalue調(diào)用它,會觸發(fā)編譯錯誤。 因此,這里只提供move語義。這項能力被程序庫中諸如unique pointer ,file stream 或string stream 所用。

以上意味著,如果class未提供move語義,只提供慣常的copy構(gòu)造函數(shù)和copy assignment 操作符,rvalue reference 可以調(diào)用它們。 因此std::move ()意味著"調(diào)用move語義(若有提供的話),否則調(diào)用copy語義"。

返回Rvalue Reference

你不需要也不應(yīng)該move()返回值。C++ standard指出,對于以下代碼

X foo(){X x;return x; }

保證有以下行為:

  • 如果X有一個可取用的copy或move構(gòu)造函數(shù),編譯器可以選擇略去其中的copy版本。這也就是所謂的return value optimization(RVO),這個特性甚至在C++11之前就獲得了大多數(shù)編譯器的支持。
  • 否則,如果X有一個move構(gòu)造函數(shù),X就被moved(搬移)。
  • 否則,如果X有一個copy構(gòu)造函數(shù),X就被copied(復(fù)制).
  • 否則,報出一個編譯期錯誤(compile-time error)。

也請注意,如果返回的是個Local nonstatic 對象,那么返回其rvalue reference 是不對的:

X&& foo(){X x;...return x;//ERROR:returns reference to nonexisting object }

是的,rvalue reference 也是個reference ,如果返回它而它指向local對象,意味著你返回一個reference 卻指向一個不再存在的對象。是否對它使用std::move()倒是無關(guān)緊要。

3.1.6 新式的字符串字面常量(String Literal)

自C++11起,你可以定義raw string 和multibyte/wide-character 等字符串字面常量。

Raw String Literal

Raw string允許我么能定義字符序列(character sequence),做法是確切寫下其內(nèi)容使其成為一個raw character sequence。于是你可以省下很多用來裝飾特殊字符的escape符號。

Raw string 以R"(開頭,以)" 結(jié)尾,可以內(nèi)含line break。例如一個用來表示“兩個反斜線和一個n”的尋常字面常量可定義如下:

"\\\\n"

也可定義它為如下raw string literal:

R"(\\n)"

如果要在raw string 內(nèi)寫出)”,可使用定義符(delimiter)。因此,一個raw string 的完整語法是R"delim(…)delim",其中delim是個字符序列,最多16個基本字符,不可含反斜線(backslash),空格(whitespace)和小括號(parenthesis)。

舉個例子,下面的raw string literal

R"nc(a\b\nc()")nc";

等同于以下的尋常string literal:

“a\\\ n b\\nc()\” \n "

這樣的string內(nèi)含1個a、1個反斜線,一個新行字符(newline),若干空格,一個b,一個反斜線,一個n,一個c,一對小括號,一個雙引號,一個新行字符,以及若干空格。

定義正則表達式時raw string literal 特別有用。

3.1.7 關(guān)鍵字noexcept

C++11提供了關(guān)鍵字noexcept,用來指明某個函數(shù)無法----或不打算----拋出異常。例如

void foo() noexcept;

聲明了foo()不打算拋出異常。 若有異常未在foo()內(nèi)被處理—亦即如果foo()拋出異常—程序會被終止,然后std::terminate()被調(diào)用并默認(rèn)調(diào)用std::abort() 。

3.1.8 關(guān)鍵字constexpr

自C++11起,constexpr可用來讓表達式核定于編譯期。例如

constexpr int square(int x){return x*x; }float a[square(9)]; //OK since C++11 :a has 81 elements

這個關(guān)鍵字修正了一個在C++98 使用數(shù)值極限時出現(xiàn)的問題,在C++11以前,以下式子

std::numeric_limits<short>::max()

無法被用作一個整型常量,雖然它在功能上等同于宏INT_MAX 。如今,在C++11中,這樣一個式子被聲明為constexpr,于是,舉個例子,你可以用它聲明array或進行編輯期運算(所謂metaprogramming):

std:;array<float,std::numeric_limits<short>::max()> a;

3.1.9 嶄新的Template 特性

Variadic Template

自C++11開始,template可擁有那種“得以接受個數(shù)不定的template實參”的參數(shù)。 此能力稱為variadic template 。舉個例子,你可以寫出這樣的print(),得以在調(diào)用它時給予不定個數(shù)的實參且各具不同的類型:

void print(){ }template <typename T,typename..Types> void print(const T&firstArg, const Types&... args){std::cout<<firstArg<<std::endl; //print first argumentprint(args...); //call print() for remaining arguments }

如果傳入1或多個實參,上述的function template 就會被調(diào)用,它會把第一實參區(qū)分開來,允許第一實參被打印,然后遞歸調(diào)用print()并傳入其余實參。你必須提供一個non-template重載函數(shù)print(),才能結(jié)束整個遞歸動作。

舉個例子,如下調(diào)用:

print(7.5, "hello", std::bitset<16>(377),42);

會導(dǎo)致以下輸出

7.5 hello 0000000101111001 42

注意,目前還在討論以下例子是否也有效,原因是,正規(guī)而言,一個“單實參的variadic形式”與一個“單實參的nonvariadic形式”形成歧義;然而編譯器通常接受這樣的代碼:

template <typename T> void print(const T&arg){std::cout<<arg<<std::endl; }template<typename T,typename ..Types>void print(const T& firstArg,const Types&... args){std::cout<<firstArg <<std::endl;//print first argumentprint(args...); //call print() for remaining arguments }

在variadic template 內(nèi),sizeof…(args)會生成實參個數(shù)。

Class std:: tuple<> 大量使用了這一特性。

Alias Template(帶別名的模板,或者叫Template Typedef)

自C++11 起,支持template(partial) type definition 。然而由于關(guān)鍵字typename 用于此處時總是出于某種原因而失敗,所以這里引入關(guān)鍵字using ,并因此引入一個新術(shù)語alias template 。舉個例子,寫出如下代碼

template<typename T> using Vec=std::vector<T,MyAlloc<T>>;//standard vector using own allocator

之后,Vec< int > coll; 就等價于std::vector<int,MyAlloc< int>> coll;

其他的Template新特性

自C++11起,function template可擁有默認(rèn)的template實參。此外,local type可被當(dāng)作template實參。

3.1.10 Lambda

C++11引入了lambda,允許inline函數(shù)的定義式被用作一個參數(shù),或是一個local對象。

Lambda改變了C++標(biāo)準(zhǔn)庫的用法。

Lambda的語法

所謂lambda是一份功能定義式,可被定義于語句(statement)或表達式(expression)內(nèi)部。因此你可以拿lambda當(dāng)作inline函數(shù)使用。

最小型的lambda函數(shù)沒有參數(shù),什么也不做,如下:

[]{std::cout<< "hello lambda" <<std::endl; }

可以直接調(diào)用它:

[]{std::cout<<"hello lambda" <<std::endl; }(); //prints "hello lambda"

或者把它傳遞給對象,使之能被調(diào)用:

auto l=[]{std::cout<<"hello lambda"<<std::endl;};l(); //prints “hello lambda”

如你所見,lambda總是由一個所謂的lambda introducer引入:那是一組方括號,你可以在其內(nèi)指明一個所謂的capture,用來在lambda內(nèi)部訪問”nonstatic外部對象“。如果無需訪問外部數(shù)據(jù),這組方括號可以為空。Static對象,諸如cout,是可被使用的。

在lambda introducer 和lambda body之間,你可以指明參數(shù)或mutable,或一份異常明細(xì)(exception specification)或attribute specifier以及返回類型。所有這一切都可有可無,但如果其中一個出現(xiàn)了,參數(shù)所需的小括號就必須出現(xiàn)。 因此lambda語法也可以是:
[…] {…}


[…] (…)

Lambda 可以擁有參數(shù),指明于小括號內(nèi),就像任何函數(shù)一樣:

auto l=[](const std::string& s){std::cout<<s<<std::endl; }; l("hello lambda");

然而,請注意,lambda不可以是template,你始終必須指明所有類型。

lambda也可以返回某物。但你不需要指明返回類型,該類型會根據(jù)返回值被推導(dǎo)出來。例如下面的lambda的返回類型是int:

[]{return 42; }

如果一定想指明一個返回類型,可使用新式C++語法

[]() -> double{return 42; }

會返回42.0
這里指明返回類型,放在實參所需要的小括號以及 字符->以后

下面是一個lambda表達式的使用用例:

auto num=[](const int & n){return n;};auto n=num(2);cout<<n<<endl;

輸出結(jié)果:2

Capture(用以訪問外部作用域)

在lambda introducer(每個lambda最開始的方括號)內(nèi),你可以指明一個capture用來處理外部作用域內(nèi)未被傳遞為實參的數(shù)據(jù):

  • [=]意味著外部作用域以by value方式傳遞給lambda。因此當(dāng)這個lambda被定義時,你可以讀取所有可讀數(shù)據(jù),但不能改動它們。
  • [&]意味著外部作用域以 by reference 方式傳遞給lambda。因此當(dāng)這個lambda被定義時,你對所有數(shù)據(jù)的涂寫動作都是合法的,前提是你擁有涂寫它們的權(quán)力。

也可以個別指明lambda之內(nèi)你所訪問的每一個對象是by value或 by reference。因此你可以對訪問設(shè)限,也可以混合不同的訪問權(quán)力。例如下面這些語句:

int x=0; int y=42; auto qqq=[x,&y]{cout<<"x: "<<x<<endl;cout<<"y: "<<y<<endl;++y;} x=y=77;qqq(); qqq();cout<<"final y: "<<y<<endl;

輸出結(jié)果

你也可以寫[=,&y] 取代[x,&y],意思是以by reference 方式傳遞y,其他所有實參則以by value 方式傳遞。

為了獲得passing by value 和passing by reference 混合體,你可以聲明lambda為mutable。下例中的對象都以by value 方式傳遞,但在這個lambda 所定義的函數(shù)對象內(nèi),你有權(quán)利涂寫傳入的值。

例如

int id=0; auto f=[id] () mutable{cout<<"id: "<<id<<endl;++id;}; id =42; f(); f(); f(); cout<<id<<endl;

輸出結(jié)果

可以把上述lambda的行為視同下面這個function object

class{private:int id;// copy of outside idpublic:void operator(){cout<<"id: "<<id<<endl;++id;} };

由于mutable的緣故,operator()被定義為一個non-const成員函數(shù),那意味著對id的涂寫是可能的。 所以,有了mutable,lambda變得stateful,即使state是以 by value方式傳遞。 如果沒有指明mutable(一般往往如此),operator()就成為一個const成員函數(shù),那么對于對象你就只能讀取,因為它們都是以值傳遞的。

總結(jié)

以上是生活随笔為你收集整理的C++11语言新特性-《C++标准库(第二版)》读书笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。