1. <li id="3se62"></li>
      <th id="3se62"></th>

      <progress id="3se62"></progress>
         你好,歡迎來到電腦編程技巧與維護雜志社! 雜志社簡介廣告服務讀者反饋編程社區  
        合訂本訂閱
         
         
        您的位置:技術專欄 / C專欄
        VC10中的C++0x特性
         
        VC10中的C++0x特性:Lambdas,auto,以及 static_assert

            Microsoft Visual Studio 2010 九月社區技術預覽版 (CTP)所帶的Visual C++編譯器對四個C++0x語言特性提供了支持,也就是 lambdas,auto,static_assert,以及 rvalue references (右值引用,譯注:后面不再對這個詞進行翻譯)。今天,我將詳細介紹前三個特性。(很快我將貢獻一整篇幅的文章來解釋右值引用,僅僅是因為再在這里解釋的話將會加大這篇已經很長的文章的篇幅)

            首先,說明一些事情:

            1,今天的這篇文章是由 Stephan T. Lavavej,Visual C++庫的開發人員以及C, A, 與 T讀者投書欄帶給你們的。注意作為庫的開發人員,我并沒有實現這些特性。那是 Jonathan Caves,前端編譯器開發者,選舉標準委員會成員以及所有“忍者”(鮮為人知的高手)的成果。

            2,我將 Visual C++ compiler in VS 2010 簡稱為 VC10 ( VS 2008 包含 VC9,VS 2005 包含 VC8,等等。 - 10 并不比 2010 簡短)

            3,C++0x 指的是即將到來的 C++ 標準,現在還在起草中。(C++標準委員會希望它可以在 2009 年完成,稱作 C++ 09;玩笑話說如果它推遲到 2010 或者更晚的話,“x” 將是十六進制的了)。 C++ 98 和C++ 03 指的是當前的 C++ 標準。(在這里不回顧歷史了, C++ 標準 2003 僅僅是最初的 C++ 1998 標準 的“補丁”版,對大部分人來說可以忽略兩者間的區別。C++ 03 和 C++ 0x 模樣雖然看起來差不多,但完全不同)

            4,我要感謝標準委員會開發出這些奇妙而有用并富有藝術的特性。他們也在以下站點上提供了重要的文檔:

            C++0x 語言特性:

            http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2705.html

            C++0x 庫特性:http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2706.html

            C++0x 進行中的草案:

            http://open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2798.pdf

            5,總是會有bug的(雖然希望不會太多),這也就是發布 CTP 版本的主要目的(讓用戶測試發現 bug )。請通過 Microfsoft 把這些 bug 報告給我們。

            現在,讓我們來審視這些特性吧!

            lambdas

            在 C++ 0x 中,“lambda 表達式”隱式定義并構建不具名函數對象,這些對象就像手寫函數對象一樣。下面是 lambda “Hello,World”入門級的示例:

         C:\Temp>type meow.cpp

        #include <algorithm>

        #include <iostream>

        #include <ostream>

        #include <vector>

        using namespace std;

         

        int main() {

            vector<int> v;

         

            for (int i = 0; i < 10; ++i) {

                v.push_back(i);

            }

         

            for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

            cout << endl;

        }

        C:\Temp>cl /EHsc /nologo /W4 meow.cpp > NUL && meow

        0 1 2 3 4 5 6 7 8 9


         
            [] 操作符是 lambda 導引符, 它告訴編譯器一個 lambda 表達式開始了。 (int n) 是 lambda 參數聲明,它告訴編譯器不具名函數對象類的函數調用操作符帶有哪些參數, { cout << n << " "; }  是復合聲明,它是不具名函數對象類的函數調用操作符的函數體。不具名函數對象類的函數調用操作符默認返回 void.

            這樣,C++0x 在內部將它轉換成如你在C++ 98 下編寫的一樣代碼:

        C:\Temp>type meow98.cpp

        #include <algorithm>

        #include <iostream>

        #include <ostream>

        #include <vector>

        using namespace std;

         

        struct LambdaFunctor {

            void operator()(int n) const {

                cout << n << " ";

            }

        };

         

        int main() {

            vector<int> v;

         

            for (int i = 0; i < 10; ++i) {

                v.push_back(i);

            }

         

            for_each(v.begin(), v.end(), LambdaFunctor());

            cout << endl;

        }

         

        C:\Temp>cl /EHsc /nologo /W4 meow98.cpp > NUL && meow98

        0 1 2 3 4 5 6 7 8 9

            現在我將不再累述類似“不具名函數對象類的函數調用操作符默認返回 void”這樣的話,開始換用“lambda 函數返回 void”的說法,但是記住 lambda 表達式做了些什么是很重要的,那就是:定義類并構建對象。

            當然,lambda 的復合聲明部分(函數體部分)可以包含多個聲明語句,譬如:

        C:\Temp>type multimeow.cpp

        #include <algorithm>

        #include <iostream>

        #include <ostream>

        #include <vector>

        using namespace std;

         

        int main() {

            vector<int> v;

         

            for (int i = 0; i < 10; ++i) {

                v.push_back(i);

            }

         

            for_each(v.begin(), v.end(), [](int n) {

                cout << n;

         

                if (n % 2 == 0) {

                    cout << " even ";

                } else {

                    cout << " odd ";

                }

            });

         

            cout << endl;

        }


        C:\Temp>cl /EHsc /nologo /W4 multimeow.cpp > NUL && multimeow

        0 even 1 odd 2 even 3 odd 4 even 5 odd 6 even 7 odd 8 even 9 odd


         
            lambda 函數也并不總是必須返回 void.如果 lambda 的復合聲明語句像是這樣的 { return expression; } ,那么 lambda 的返回類型就會自動地被推斷成 expression 的類型。

        C:\Temp>type cubicmeow.cpp

        #include <algorithm>

        #include <deque>

        #include <iostream>

        #include <iterator>

        #include <ostream>

        #include <vector>

        using namespace std;

         

        int main() {

            vector<int> v;

         

            for (int i = 0; i < 10; ++i) {

                v.push_back(i);

            }

            deque<int> d;

            transform(v.begin(), v.end(), front_inserter(d), [](int n) { return n * n * n; });

         

            for_each(d.begin(), d.end(), [](int n) { cout << n << " "; });

            cout << endl;

        }

        C:\Temp>cl /EHsc /nologo /W4 cubicmeow.cpp > NUL && cubicmeow

        729 512 343 216 125 64 27 8 1 0


         
            在這里,  n * n * n 的類型是 int,所以 lambda 函數返回 int.

            有著復雜復合聲明語句的 lambda 函數不會自動推斷返回類型,你必須顯式指定返回類型。

           C:\Temp>type returnmeow.cpp

        #include <algorithm>

        #include <deque>

        #include <iostream>

        #include <iterator>

        #include <ostream>

        #include <vector>

        using namespace std;

         

        int main() {

            vector<int> v;

         

            for (int i = 0; i < 10; ++i) {

                v.push_back(i);

            }

         

            deque<double> d;

         

            transform(v.begin(), v.end(), front_inserter(d), [](int n) -> double {

                if (n % 2 == 0) {

                    return n * n * n;

                } else {

                    return n / 2.0;

                }

            });

         

            for_each(d.begin(), d.end(), [](double x) { cout << x << " "; });

            cout << endl;

        }

        C:\Temp>cl /EHsc /nologo /W4 returnmeow.cpp > NUL && returnmeow

        4.5 512 3.5 216 2.5 64 1.5 8 0.5 0

            -> double 是可選的 lambda 返回類型從句。為什么它不放在左邊(譯注:返回類型一般在函數左邊聲明),就像程序員一直以來在C函數中做的那樣?因為那樣的話 lambda 導引符 [] 就不會第一個出現了,而正是它告訴編譯器一個 lambda 函數開始了。(核心工作組最擅長解決這樣的問題;嘗試猜測C++ 中一個給定的概念是否是可被解析的會讓我頭疼。)

            如果忘記了指定 lambda返回類型從句,編譯器就會抱怨每一個返回語句:

         C:\Temp>cl /EHsc /nologo /W4 borkedreturnmeow.cpp

        borkedreturnmeow.cpp

        borkedreturnmeow.cpp(20) : error C3499: a lambda that has been specified to have a void return type cannot return a value

        borkedreturnmeow.cpp(22) : error C3499: a lambda that has been specified to have a void return type cannot return a value

            到目前為止我所介紹的 lambda 都是無狀態的:它們不包含數據成員。你也可以有有狀態的 lambda,這是通過“傳遞”(原文用加引號的 capturing 這個詞,在這里我翻譯成傳遞似乎不太妥,故我都加括號引用原文,下同)局部變量來實現的?盏 lambda 導引符 [] 意味著“一個無狀態的 lambda”,但在 lambda 導引符 [] 中你可以指定 capture-list :

         C:\Temp>type capturekittybyvalue.cpp

        #include <algorithm>

        #include <iostream>

        #include <ostream>

        #include <vector>

        using namespace std;

         

        int main() {

            vector<int> v;

         

            for (int i = 0; i < 10; ++i) {

                v.push_back(i);

            }
         

            int x = 0;

            int y = 0;

            // op>>() leaves newlines on the input stream,

            // which can be extremely confusing. I recommend

            // avoiding it, and instead using non-member

            // getline(cin, str) to read whole lines and

            // then parse them. But in the interests of

            // brevity, I’ll use evil op>>():

            cout << "Input: ";

            cin >> x >> y;

            v.erase(remove_if(v.begin(), v.end(), [x, y](int n) { return x < n && n < y; }), v.end());

            for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

            cout << endl;

        }

        C:\Temp>cl /EHsc /nologo /W4 capturekittybyvalue.cpp > NUL && capturekittybyvalue

        Input: 4 7

        0 1 2 3 4 7 8 9

            如果你忘記了capture-list,編譯器就會抱怨:

         C:\Temp>cl /EHsc /nologo /W4 borkedcapturekittybyvalue.cpp

        borkedcapturekittybyvalue.cpp

        borkedcapturekittybyvalue.cpp(27) : error C3493: ’x’ cannot be implicitly captured as no default capture mode has been specified

        borkedcapturekittybyvalue.cpp(27) : error C3493: ’y’ cannot be implicitly captured as no default capture mode has been specified

            (我很快就會解釋默認的傳遞(capture))

            記著,lambda 表達式隱式地定義了一個不具名函數對象類。復合聲明語句 { return x < n && n < y; } 在這個類中被當作函數調用操作符的函數體。雖然從詞法結構上看復合聲明語句是在 main() 塊之內,但在概念上它是在 main() 塊之外的,因此如果不傳遞(capture)到 lambda 中去,就不能在其中使用來自main() 中的局部變量。

            上面的代碼在內部被翻譯成:

         C:\Temp>type capturekittybyvalue98.cpp

        #include <algorithm>

        #include <iostream>

        #include <iterator>

        #include <ostream>

        #include <vector>

        using namespace std;

         

        class LambdaFunctor {

        public:

            LambdaFunctor(int a, int b) : m_a(a), m_b(b) { }

         

            bool operator()(int n) const { return m_a < n && n < m_b; }

         

        private:

            int m_a;

            int m_b;

        };

         

        int main() {

            vector<int> v;

         

            for (int i = 0; i < 10; ++i) {

                v.push_back(i);

            }

         

            int x = 0;

            int y = 0;

         

            cout << "Input: ";

            cin >> x >> y; // EVIL!

         

            v.erase(remove_if(v.begin(), v.end(), LambdaFunctor(x, y)), v.end());

         

            copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));

            cout << endl;

        }

         

        C:\Temp>cl /EHsc /nologo /W4 capturekittybyvalue98.cpp > NUL && capturekittybyvalue98

        Input: 4 7

        0 1 2 3 4 7 8 9

         
            在這里你可以清楚地看到是“按值”傳遞(captures)的。函數對象存儲了局部變量的拷貝。這就使得函數對象可以比通過傳遞(capture)來創建它們的局部變量有更長的生命期。但是,要注意:(a)在 lambda 中不能修改通過傳遞(capture)獲得的拷貝,因為默認情況下函數調用操作符是 const 屬性的,(b)一些對象的拷貝開銷是昂貴的,(c)局部變量的更新不會反應到通過傳遞(capture)獲得的拷貝(在語義上它們是原始值)。很快我就會解釋如有需要應該如何來處理以上情況。

          推薦精品文章

        ·2023年7月目錄
        ·2023年6月目錄 
        ·2023年5月目錄
        ·2023年4月目錄 
        ·2023年3月目錄 
        ·2023年2月目錄 
        ·2023年1月目錄 
        ·2022年12月目錄 
        ·2022年11月目錄 
        ·2022年10月目錄 
        ·2022年9月目錄 
        ·2022年8月目錄 
        ·2022年7月目錄 
        ·2022年6月目錄 

          聯系方式
        TEL:010-82561037
        Fax: 010-82561614
        QQ: 100164630
        Mail:gaojian@comprg.com.cn

          友情鏈接
         
        Copyright 2001-2010, www.1wcdp.top, All Rights Reserved
        京ICP備14022230號-1,電話/傳真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
        地址:北京市海淀區遠大路20號寶藍大廈E座704,郵編:100089 
        1. <li id="3se62"></li>
          <th id="3se62"></th>

          <progress id="3se62"></progress>
            操美女小骚逼