C++11常用特性學習-易學易用新特性(>>/auto/decltype/範圍的for)

C11易學易用新特性

C11中有些特性例如auto類型推導、基於範圍的for範圍等非常易用的特性,非常具有親和力,也能夠顯著的提高編碼效率,已經基本都被目前主流編譯器使用。規範這些特性的使用,可以顯著提高效率,在跨平臺和可讀性上也沒有太大影響(auto等濫用會影響可讀性)。

右尖括號]的改進

C++03的解析器都把”>>”定義爲右移運算符.但是,在嵌套的模板聲明中,程序員往往傾向於忽略兩個右尖括號之間的空格,如:Y<X<1> > x1。這會導致編譯器報一個語法錯誤。C11改進了編譯器的解析規則,儘可能地將多個右尖括號(>)解析成模板參數結束符.可以用圓括號來改變這個規則,圓號的優先級比它高。在真的進行右移時要用圓括號括起來,不然會導致C98/03和C11的兼容性問題。如:X< 1 >> 5> x;在C03和C11編譯解釋就不同,應該爲X< (1 >> 5)> x
來避免兼容性問題;

auto類型推導

C++一般會認爲是強類型的語言(對比shell和JavaScript等語言),變量的類型和定義必須是強制定義的,變量之間的數據必須是可以強制轉化的,當在某些應用過程中,弱類型的特性可以極大的提高編寫特性和可讀性。C++11的auto關鍵字可以實現類型由推導得出。例如下面代碼:

#include <iostream>
using namespace std;
int main() {
    auto name = "world.\n";
    cout  << "hello," << name;
}

auto用於宏的一個實用例子:

 #define Max1(a, b) ((a) > (b)) ? (a) : (b)//遇見一個宏替換a或b就要計算一次a或b
#define Max2(a, b) ({ \
        auto _a = (a); \  //這裏將宏替換a的計算結果先保存至_a中,這樣減少了計算開銷
        auto _b = (b); \
        (_a > _b) ? _a: _b; })

int main() {
    int m1 = Max1(1*2*3*4, 5+6+7+8);
    int m2 = Max2(1*2*3*4, 5+6+7+8);//計算開銷減小
}

用在STL等循環中可以極大提高開發效率和可讀性:

#include <string>
#include <vector>
void looper(std::vectot<std::string> & vs) {
    for (auto i = vs.begin(); i < vs.end();i++){

    }
}

auto用在模板編程可以結局很多例如精度,裝換等問題。但要避免語法二義性等爲題。

decltype和typeid

typeid主要是爲了得到一些數據的type_info的數據,程序員可以在調試等使用typeid得到一個變量的類型等信息(typeid);如a爲程序範圍內可用變量,typeid(a).name()得到類型的明,typeid(a).hashcode()得到哈希值。

與auto類型,decltype也能進行類型的推導,如定義與X相同類型的Y變量:
decltype(X) Y;
ptrdiff_t是C/C++標準庫中定義的一個與機器相關的數據類型。ptrdiff_t類型變量通常用來保存兩個指針減法操作的結果,ptrdiff_t定義在stddef.h(cstddef)這個文件內。ptrdiff_t通常被定義爲long int類型。以及其他結果的定義如下:
using size_t = decltype(sizeof(0));
using prtdiff_t = decltype((int*)0 - (int*)0);
using nullptr_t = decltype(nullptr);

關於使用auto和decltype需要注意的地方參見: C++11: 新手易學,老兵易用

基於範圍的for循環

在C++03中,要遍歷一個list中的元素需要很多代碼,Java等語言可以使用foreach來進行迭代,C11也引入了for的範圍循環對元素進行遍歷;如遍歷、對每個元素加倍:

#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<int> v = {1, 2, 3, 4, 5};
    for (auto i = v.begin(); i != v.end(); ++i)
        cout << *i << endl;     // i是迭代器對象

    for (auto e: v)//冒號分開,前面部分是範圍內用於迭代的變量,後半部分是迭代的範圍,只能用於明確已知迭代範圍
        cout << e << endl;      // e是解引用後的對象

         int my_array[5] = {1, 2, 3, 4, 5};
    // double the value of each element in my_array:
       for (int &x : my_array) 
        {
              x *= 2;
         }
}

注意:對迭代範圍不確定準呢過使用for的迭代循環:

#include <iostream>
using namespace std;

int func(int a[]) {

    for (auto e: a) // 編譯失敗,迭代範圍不確定
        cout << e;
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    func(arr);
}

標準庫已經有了for_each:
for_each( InputIt first, InputIt last, UnaryFunction f );

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章