
什么是C++11
C++11是以前被叫做C++0x,是對眼下C++語言的擴展和修正。C++11不僅包括核心語言的新機能,並且擴展了C++的標准程序庫(STL)。並入了大部分的C++ Technical Report 1(TR1)程序庫(數學的特殊函數除外)。
C++11包含大量的新特性:包含lambda表達式,類型推導keywordauto、decltype,和模板的大量改進。
本文將對C++11的以上新特性進行簡單的解說。以便大家可以高速了解到C++11對C++的易用性方面祈禱的巨大作用。
新的keyword
auto
C++11中引入auto第一種作用是為了自己主動類型推導
auto的自己主動類型推導,用於從初始化表達式中判斷出變量的數據類型。通過auto的自己主動類型推導,能夠大大簡化我們的編程工作
auto實際上實在編譯時對變量進行了類型推導,所以不會對程序的執行效率造成不良影響
另外,似乎auto並不會影響編譯速度,由於編譯時本來也要右側推導然后推斷與左側是否匹配。
auto a; // 錯誤,auto是通過初始化表達式進行類型推導,假設沒有初始化表達式,就無法確定a的類型 auto i = 1; auto d = 1.0; auto str = "Hello World"; auto ch = 'A'; auto func = less<int>(); vector<int> iv; auto ite = iv.begin(); auto p = new foo() // 對自己定義類型進行類型推導
auto不光有以上的應用,它在模板中也是大顯身手。比方下例這個加工產品的樣例中。假設不使用auto就必須聲明Product這一模板參數:
template <typename Product, typename Creator> void processProduct(const Creator& creator) { Product* val = creator.makeObject(); // do somthing with val } .
假設使用auto,則能夠這樣寫:
template <typename Creator> void processProduct(const Creator& creator) { auto val = creator.makeObject(); // do somthing with val }
拋棄了麻煩的模板參數,整個代碼變得更加整潔了。
decltype
decltype實際上有點像auto的反函數,auto能夠讓你聲明一個變量。而decltype則能夠從一個變量或表達式中得到類型,有實比例如以下:
int x = 3; decltype(x) y = x;
有人會問,decltype的有用之處在哪里呢。我們接着上邊的樣例繼續說下去。假設上文中的加工產品的樣例中我們想把產品作為返回值該怎么辦呢?我們能夠這樣寫:
template <typename Creator> auto processProduct(const Creator& creator) -> decltype(creator.makeObject()) { auto val = creator.makeObject(); // do somthing with val }
nullptr
nullptr是為了解決原來C++中NULL的二義性問題而引進的一種新的類型,由於NULL實際上代表的是0,
void F(int a){ cout<<a<<endl; } void F(int *p){ assert(p != NULL); cout<< p <<endl; } int main(){ int *p = nullptr; int *q = NULL; bool equal = ( p == q ); // equal的值為true,說明p和q都是空指針 int a = nullptr; // 編譯失敗,nullptr不能轉型為int F(0); // 在C++98中編譯失敗。有二義性。在C++11中調用F(int) F(nullptr); return 0; }
序列for循環
在C++中for循環能夠使用類似java的簡化的for循環,能夠用於遍歷數組。容器,string以及由begin和end函數定義的序列(即有Iterator),演示樣例代碼例如以下:
map<string, int> m{{"a", 1}, {"b", 2}, {"c", 3}}; for (auto p : m){ cout<<p.first<<" : "<<p.second<<endl; }
Lambda表達式
lambda表達式類似Javascript中的閉包,它能夠用於創建並定義匿名的函數對象,以簡化編程工作。Lambda的語法例如以下:
[函數對象參數](操作符重載函數參數)->返回值類型{函數體}
vector<int> iv{5, 4, 3, 2, 1}; int a = 2, b = 1; for_each(iv.begin(), iv.end(), [b](int &x){cout<<(x + b)<<endl;}); // (1) for_each(iv.begin(), iv.end(), [=](int &x){x *= (a + b);}); // (2) for_each(iv.begin(), iv.end(), [=](int &x)->int{return x * (a + b);});// (3)
- []內的參數指的是Lambda表達式能夠取得的全局變量。(1)函數中的b就是指函數能夠得到在Lambda表達式外的全局變量,假設在[]中傳入=的話,即是能夠取得全部的外部變量,如(2)和(3)Lambda表達式
- ()內的參數是每次調用函數時傳入的參數。
- ->后加上的是Lambda表達式返回值的類型。如(3)中返回了一個int類型的變量
變長參數的模板
我們在C++中都用過pair,pair能夠使用make_pair構造,構造一個包括兩種不同類型的數據的容器。比方,例如以下代碼:
auto p = make_pair(1, "C++ 11");
因為在C++11中引入了變長參數模板,所以發明了新的數據類型:tuple,tuple是一個N元組。能夠傳入1個, 2個甚至多個不同類型的數據
auto t1 = make_tuple(1, 2.0, "C++ 11"); auto t2 = make_tuple(1, 2.0, "C++ 11", {1, 0, 2});
這樣就避免了從前的pair中嵌套pair的丑陋做法。使得代碼更加整潔
還有一個常常見到的樣例是Print函數,在C語言中printf能夠傳入多個參數。在C++11中,我們能夠用變長參數模板實現更簡潔的Print
template<typename head, typename... tail> void Print(Head head, typename... tail) { cout<< head <<endl; Print(tail...); }
Print中能夠傳入多個不同種類的參數,例如以下:
Print(1, 1.0, "C++11");
更加優雅的初始化方法
在引入C++11之前。僅僅有數組能使用初始化列表,其它容器想要使用初始化列表,僅僅能用下面方法:
int arr[3] = {1, 2, 3} vector<int> v(arr, arr + 3);
int arr[3]{1, 2, 3}; vector<int> iv{1, 2, 3}; map<int, string>{{1, "a"}, {2, "b"}}; string str{"Hello World"};