C++ 11中幾個我比較喜歡的語法(二)


之前在文章C++ 11中幾個我比較喜歡的語法中介紹了幾個我比較喜歡的C++語法,其中有些語法由於VC 11還不支持,無法跨平台,所以沒有介紹。前幾天VS 2013 Preview發布后,對C++ 11又有了一些支持,因此這里繼續完成一下C++ 11語法系列:

原生字符串(raw string literals)

很多時候,當我們只需要一行字符串的時候,字符串轉義往往成了一個負擔,和寫和讀都帶了很大的不便。例如,對於如下路徑"C:\Program Files\Microsoft.NET\ADOMD.NET",我們必須把它寫成如下形式:

    string path = "C:\\Program Files\\Microsoft.NET\\ADOMD.NET";

可能你會說這個並沒有多大影響,下面這個正則表達式的例子呢?你能看出來原文到底是什么嗎?

    string exp = "('(?:[^\\\\']|\\\\.)*'|\"(?:[^\\\\\"]|\\\\.)*\")|";

在C#中,我們可以通過@關鍵字來取消字符串轉義。現在,在C++ 11中,也增加了這樣的語法。對於前面的例子,它的非轉義形式為:

    string path = R"(C:\Program Files\Microsoft.NET\ADOMD.NET)";

從上面的例子中可以看出,它的語法格式如下:

  1. 字符串前加'R'前綴
  2. 字符串首尾加上括號()

它的語法格式比C#的@前綴要稍微復雜點,不過這個復雜也有復雜的好處,那就是字符串里面可以帶引號,例如:

    string path = R"(this "word" is escaped)";

而C#就無法保持原始字符串格式,對引號仍需要轉義:

    string path = @"this ""word"" is escaped";

 

委托構造函數(Delegating constructors

C++的構造是不能復用的,為了復用其初始化操作,我們往往會增加一個Initial函數:

    class Foo
    {
    private:
        int A;

    public:
        Foo() : A(0)
        {
            Init();
        }
        Foo(int a) : A(a)
        {
            Init();
        }

    private:
        void Init()
        {
            // do something
        }
    };

這樣一來就增加了一個只調用一次的Init函數,並且一旦這個Init函數被其它成員函數調用的話,可能導致重復初始化,也是一個隱患。PS:本例比較簡單,通過構造函數默認參數也可以解決構造函數復用問題,但默認參數也有一些局限和帶來一些問題,限於篇幅就不做更多的討論了。

在C++ 11中,引入了委托構造函數的語法,其功能和C#中的this構造函數非常類似,就是語法上稍有差異:

    class Foo
    {
    private:
        int A;

    public:
        Foo() : Foo(0)
        {
        }
        Foo(int a) : A(a)
        {
            // do something
        }
    };

 

初始化列表(initializer list)

在C++ 03中,可以用列表的形式來初始化數組,這種方式非常直觀,但只能適用於數組,不能適用於我們自定義的容器:

    int anArray[5] = { 3, 2, 7, 5, 8 }; // ok

    std::vector<int> vArray = { 3, 2, 7, 5, 8 }; // not ok

在C++ 11中,我們則可以使得我們自定義的容器對象支持這種列表的形式的初始化方式:

    template <typename T>
    class MyArray
    {
    private:
        vector<T> m_Array;

    public:
        MyArray() { }

        MyArray(const initializer_list<T>& il)
        {
            for (auto x : il)
                m_Array.push_back(x);
        }
    };

    void main()
    {
        MyArray<int> foo = { 3, 4, 6, 9 };
    }

 

統一初始化(Uniform initialization)

C++的對象初始化方式是非常多樣的:

    int a = 2;        //"賦值風格"的初始化
    int aa [] = { 2, 3 }; //
用初始化列表進行的賦值風格的初始化
    complex z(1, 2);    //"
函數風格"的初始化

C++ 11中,允許通過以花括號的形式來調用構造函數。這樣多種對象構造方式便可以統一起來了:

    int a = { 2 };   
    int aa [] = { 2, 3 };  

    complex z = { 1, 2 }; 

值得一提的是,這種花括號的構造方式還可以用於函數的參數和返回值的類型推導,非常簡潔。

    void useMyStruct(MyStruct x)
    {
    }
    useMyStruct({ 2, 3.5f });

    MyStruct makeMyStruct(void)
    {
        return { 2, 3.5f };
    }

不過鑒於園子里不少人對C#的var的反感度,估計很多人又要對這種方式高舉反對大旗了。

 

VC對C++ 11的支持情況

由於VS 2013還是Preview階段,對於c++ 11特性支持還是不全,在今年發布的RTM版本中還會增加 幾個特性:

上到了RTM版本后,主要的常用的特性基本上都支持了。剩余的部分,則會在后續的版本中給予支持,如下是VC的RoadMap:http://video.ch9.ms/sessions/build/2013/2-306.pptx,連C++ 14的支持計划也列出來了。總體上感覺MS還是還是比較給力的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM