青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

羅朝輝(飄飄白云)

關(guān)注嵌入式操作系統(tǒng),移動平臺,圖形開發(fā)。-->加微博 ^_^

  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
  85 隨筆 :: 0 文章 :: 169 評論 :: 0 Trackbacks

【譯】VC10中的C++0x特性 Part 1:Lambdas,auto,以及 static_assert

來源:vcblog 作者:Stephan T. Lavavej 翻譯:飄飄白云  

(轉(zhuǎn)載時請注明作者和出處。未經(jīng)許可,請勿用于商業(yè)用途)

簡介

這一系列文章介紹Microsoft Visual Studio 2010 中支持的C++ 0x特性,目前有三部分。
Part 1 :介紹了Lambdas, 賦予新意義的auto,以及 static_assert;
Part 2( , , ):介紹了右值引用(Rvalue References);
Part 3:介紹了表達式類型(decltype)

VC10中的C++0x特性 Part 1,2,3 譯文打包下載(doc 和 pdf 格式): 點此下載


本文為 Part 1。

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

 


首先,說明一些事情:


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

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

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

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

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的(雖然希望不會太多),這也就是發(fā)布 CTP 版本的主要目的(讓用戶測試發(fā)現(xiàn) bug )。請通過 Microfsoft 把這些 bug 報告給我們。

現(xiàn)在,讓我們來審視這些特性吧!

 lambdas

在 C++ 0x 中,“lambda 表達式”隱式定義并構(gòu)建不具名函數(shù)對象,這些對象就像手寫函數(shù)對象一樣。下面是 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 參數(shù)聲明,它告訴編譯器不具名函數(shù)對象類的函數(shù)調(diào)用操作符帶有哪些參數(shù), { cout << n << " "; }  是復合聲明,它是不具名函數(shù)對象類的函數(shù)調(diào)用操作符的函數(shù)體。不具名函數(shù)對象類的函數(shù)調(diào)用操作符默認返回 void。


這樣,C++0x 在內(nèi)部將它轉(zhuǎn)換成如你在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


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


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


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 函數(shù)也并不總是必須返回 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 函數(shù)返回 int。

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


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 返回類型從句。為什么它不放在左邊(譯注:返回類型一般在函數(shù)左邊聲明),就像程序員一直以來在C函數(shù)中做的那樣?因為那樣的話 lambda 導引符 [] 就不會第一個出現(xiàn)了,而正是它告訴編譯器一個 lambda 函數(shù)開始了。(核心工作組最擅長解決這樣的問題;嘗試猜測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 都是無狀態(tài)的:它們不包含數(shù)據(jù)成員。你也可以有有狀態(tài)的 lambda,這是通過“傳遞”(原文用加引號的 capturing 這個詞,在這里我翻譯成傳遞似乎不太妥,故我都加括號引用原文,下同)局部變量來實現(xiàn)的。空的 lambda 導引符 [] 意味著“一個無狀態(tài)的 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 表達式隱式地定義了一個不具名函數(shù)對象類。復合聲明語句 { return x < n && n < y; } 在這個類中被當作函數(shù)調(diào)用操作符的函數(shù)體。雖然從詞法結(jié)構(gòu)上看復合聲明語句是在 main() 塊之內(nèi),但在概念上它是在 main() 塊之外的,因此如果不傳遞(capture)到 lambda 中去,就不能在其中使用來自main() 中的局部變量。


上面的代碼在內(nèi)部被翻譯成:

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


但是首先,你可以“按值傳遞(capture)任何東西”,而不用特別指明每一個你想要傳遞(capture)的局部變量。其語法是使用這種形式的 lambda 導引符 [=] (默認傳遞(capture-default) = 應該可以讓你想起賦值或者拷貝初始化 Foo foo = bar; 雖然這里的拷貝實際上是直接初始化(通過初始化列表進行賦值),就像上面的 m_a(a))。


C:\Temp>type defaultcapturekittybyvalue.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;

 

    cout << "Input: ";

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

 

    v.erase(remove_if(v.begin(), v.end(), [=](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 defaultcapturekittybyvalue.cpp > NUL && defaultcapturekittybyvalue

Input: 4 7

0 1 2 3 4 7 8 9


當編譯器看到 lambda 中的 x 和 y, 就會從 main() 中按值傳遞(capture)。


情形(a)要修改通過傳遞(capture)獲得拷貝該怎樣呢?默認情況下,一個 lambda 函數(shù)調(diào)用操作符是 const 屬性的,但是可以通過使用 mutable 把它變成 non-const。


C:\Temp>type capturekittybymutablevalue.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 = 1;

    int y = 1;

 

    for_each(v.begin(), v.end(), [=](int& r) mutable {

        const int old = r;

 

        r *= x * y;

 

        x = y;

        y = old;

    });

 

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

    cout << endl;

 

    cout << x << ", " << y << endl;

}

 

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

0 0 0 6 24 60 120 210 336 504

1, 1


這里是依次將 v 中前兩個元素相乘。(我得承認真的很難想出一個不用 partial_sum() 或 adjacent_difference() 表示的例子,partial_sum() 是與前面所有的元素相乘,adjacent_difference()是與前一個元素相乘)。注意到情形(d),對通過傳遞獲得的拷貝的更新操作并沒有影響局部變量(再一次,原始值語義)。


如果你想處理情形(b),(c)和(d):避免拷貝,在 lambda 中觀察局部變量的更新,以及在 lambda 中修改局部變量又該怎么做呢?在這種情況下,你會想通過引用傳遞(capture by reference)。其語法是這種形式的 lambda 導引符 [&x, &y] (你可以把它想象成  X& x, Y& y ; 那是“引用”而不是“取址”)。


C:\Temp>type capturekittybyreference.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 = 1;

    int y = 1;

 

    for_each(v.begin(), v.end(), [&x, &y](int& r) {

        const int old = r;

 

        r *= x * y;

 

        x = y;

        y = old;

    });

 

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

    cout << endl;

 

    cout << x << ", " << y << endl;

}

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

0 0 0 6 24 60 120 210 336 504

8, 9


注意與 capturekittybymutablevalue.cpp 的區(qū)別:(1),lambda 導引符是 [&x, &y] ,(2)沒有 mutable,(3),局部變量 x 和 y 最后的值是 8 和 9,反應了在 lambda 中對他們的修改。


上面的代碼在內(nèi)部被翻譯成:


C:\Temp>type capturekittybyreference98.cpp

#include <algorithm>

#include <iostream>

#include <iterator>

#include <ostream>

#include <vector>

using namespace std;

 

#pragma warning(push)

#pragma warning(disable: 4512) // assignment operator could not be generated

 

class LambdaFunctor {

public:

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

 

    void operator()(int& r) const {

        const int old = r;

 

        r *= m_a * m_b;

 

        m_a = m_b;

        m_b = old;

    }

 

private:

    int& m_a;

    int& m_b;

};

 

#pragma warning(pop)

 

int main() {

    vector<int> v;

 

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

        v.push_back(i);

    }

 

    int x = 1;

    int y = 1;

 

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

 

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

    cout << endl;

 

    cout << x << ", " << y << endl;

}

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

0 0 0 6 24 60 120 210 336 504

8, 9


當你通過引用傳遞(capture)局部變量時,函數(shù)對象存儲局部變量的引用。這樣避免了拷貝,能夠讓函數(shù)對象觀測對局部變量的更新,以及能夠讓函數(shù)對象通過引用修改局部變量。(注意函數(shù)調(diào)用操作符是 const 屬性的,因為我們沒有把它聲明成 mutable,但這只阻止我們修改函數(shù)對象的數(shù)據(jù)成員。在這里數(shù)據(jù)成員是引用,我們無法修改它,但是我們可以修改它所指向的東西。函數(shù)調(diào)用操作符的常量性是,且一直都是,表面的)

當然,如果函數(shù)對象比用于引用傳遞的局部變量的生命期更長的話,程序會毀滅性地崩潰。(譯注:就是說引用所指向的東西已經(jīng)銷毀了,但你可能還在使用這個引用)


同樣,你可以使用默認的按引用傳遞語法;這種形式 lambder 導引符 [&] 表明“按引用傳遞”。


如果你想混合使用按值傳遞和按引用傳遞該怎么做呢?你可以像這樣聲明 [a, b, c, &d, e, &f, g],但你也可以指定默認按值傳遞,再為特定的(需要按引用傳遞的)局部變量而重載它。下面是一個修改capturekittybymutablevalue.cpp 而來的例子:


C:\Temp>type overridekitty.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 sum = 0;

    int product = 1;

 

    int x = 1;

    int y = 1;

 

    for_each(v.begin(), v.end(), [=, &sum, &product](int& r) mutable {

        sum += r;

 

        if (r != 0) {

            product *= r;

        }

 

        const int old = r;

 

        r *= x * y;

 

        x = y;

        y = old;

    });

 

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

    cout << endl;

 

    cout << "sum: " << sum << ", product: " << product << endl;

    cout << "x: " << x << ", y: " << y << endl;

}

 

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

overridekitty.cpp

0 0 0 6 24 60 120 210 336 504

sum: 45, product: 362880

x: 1, y: 1


在這里,我們想通過按值傳遞 x 和 y (因為我們只想在 lambda 內(nèi)部修改它們,而影響外部),同時我們想按傳引用捕獲 sum 和 product(因為我們確實想讓對它們的修改在外部也生效)。像這樣的 lambda 導入符組合 [&, x, y] 可以起到同樣的效果(按應用傳遞所有參數(shù),除了 x 和 y 是按值傳遞之外)


嗯,如果你想這么做又該如何?

C:\Temp>type memberkitty.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

class Kitty {

public:

    explicit Kitty(int toys) : m_toys(toys) { }

 

    void meow(const vector<int>& v) const {

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

            cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl;

        });

    }

 

private:

    int m_toys;

};

 

int main() {

    vector<int> v;

 

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

        v.push_back(i);

    }

 

    Kitty k(5);

    k.meow(v);

}

 

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

memberkitty.cpp

memberkitty.cpp(12) : error C3480: 'Kitty::m_toys': a lambda capture variable must be from an enclosing function scope


lambda 表達式語法允許你傳遞局部變量,但是數(shù)據(jù)成員不是局部變量。通過特別的方法,你也可以傳遞數(shù)據(jù)成員:


C:\Temp>type workingmemberkitty.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

class Kitty {

public:

    explicit Kitty(int toys) : m_toys(toys) { }

 

    void meow(const vector<int>& v) const {

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

            cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl;

        });

    }

 

private:

    int m_toys;

};

 

int main() {

    vector<int> v;

 

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

        v.push_back(i);

    }

 

    Kitty k(5);

    k.meow(v);

}

 

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

If you gave me 0 toys, I would have 5 toys total.

If you gave me 1 toys, I would have 6 toys total.

If you gave me 2 toys, I would have 7 toys total.


當你傳遞 this,你可以使用 m_toys,它隱含意味著 this->m_toys,就如平常一樣(譯注:作為類自身成員變量)。你也可以顯式使用 this->m_toys。(在一個 lambda 表達式內(nèi),只有當你傳遞了 this,你才能使用它;你永不可能取得 lambda 對象它自身的 this 指針)。


你也可以隱式地傳遞 this :


C:\Temp>type implicitmemberkitty.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

class Kitty {

public:

    explicit Kitty(int toys) : m_toys(toys) { }

 

    void meow(const vector<int>& v) const {

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

            cout << "If you gave me " << n << " toys, I would have " << n + m_toys << " toys total." << endl;

        });

    }

 

private:

    int m_toys;

};

 

int main() {

    vector<int> v;

 

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

        v.push_back(i);

    }

 

    Kitty k(5);

    k.meow(v);

}

 

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

If you gave me 0 toys, I would have 5 toys total.

If you gave me 1 toys, I would have 6 toys total.

If you gave me 2 toys, I would have 7 toys total.

你可以使用 [&],但它對傳遞是怎樣進行的(默認是按值)沒有影響。你不能使用 [&this]。

如果你想使用一個空無的 lambda (不帶參數(shù)),你可以省略整個 lambda參數(shù)聲明:


C:\Temp>type nullarykitty.cpp

#include <algorithm>

#include <iostream>

#include <iterator>

#include <ostream>

#include <vector>

using namespace std;

 

int main() {

    vector<int> v;

 

    int i = 0;

 

    generate_n(back_inserter(v), 10, [&] { return i++; });

 

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

    cout << endl;

 

    cout << "i: " << i << endl;

}

 

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

0 1 2 3 4 5 6 7 8 9

i: 10


這比 [&]() { return i++; } 少兩個字符。省略 lambda 參數(shù)聲明是否是良好的風格是由你來決定的。


僅博一笑,這意味著下面的代碼在 C++0x 中是合法的。


C:\Temp>type nokitty.cpp

int main() {

    [](){}();

    []{}();

}

 

上面構(gòu)建了兩個什么也不做的 lambda (一個有 lambda 參數(shù)聲明,一個沒有)并立即調(diào)用它們(通過最后一個空括號組合)。


注意可選的 lambda 參數(shù)聲明語法上包括:


( lambda-parameter-declaration-listopt ) mutableopt exception-specificationopt lambda-return-type-clauseopt


因此,如果你想使用 mutable 或  -> ReturnType,你需要在 lambda 導引符和它們之間插入空括號。


最后,因為 lambda 產(chǎn)生普通的函數(shù)對象,你可以在 tr1::function 中存儲它們。


C:\Temp>type tr1kitty.cpp

#include <algorithm>

#include <functional>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

using namespace std::tr1;

 

void meow(const vector<int>& v, const function<void (int)>& f) {

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

    cout << endl;

}

 

int main() {

    vector<int> v;

 

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

        v.push_back(i);

    }

 

    meow(v, [](int n) { cout << n << " "; });

    meow(v, [](int n) { cout << n * n << " "; });

 

    function<void (int)> g = [](int n) { cout << n * n * n << " "; };

 

    meow(v, g);

}

 

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

0 1 2 3 4 5 6 7 8 9

0 1 4 9 16 25 36 49 64 81

0 1 8 27 64 125 216 343 512 729


auto


關(guān)鍵詞 auto 是從 C++ 98 得來的,它在 C++ 98 中實際上并沒起什么作用,但在 C++ 0x 中被重用于自動類型推導(automatic type deduction)。 在一個聲明中使用 auto ,意味著“讓它和初始化它的事物具有相同的類型”。你看:


C:\Temp>type autocat.cpp

#include <iostream>

#include <map>

#include <ostream>

#include <regex>

#include <string>

using namespace std;

using namespace std::tr1;

 

int main() {

    map<string, string> m;

 

    const regex r("(\\w+) (\\w+)");

 

    for (string s; getline(cin, s); ) {

        smatch results;

 

        if (regex_match(s, results, r)) {

            m[results[1]] = results[2];

        }

    }

 

    for (auto i = m.begin(); i != m.end(); ++i) {

        cout << i->second << " are " << i->first << endl;

    }

}

 

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

cute kittens

ugly puppies

evil goblins

^Z

kittens are cute

goblins are evil

puppies are ugly


map<string, string>::iterator,你近10年的恐怖統(tǒng)治終于到頭了。

(注意:m.begin()返回 iterator,而不是 cosnt_iterator,因為 map 不是 const 屬性的。C++ 0x cbegin() 允許你從一個 non-cosnt 容器中獲得一個 const_iterator。)


lambdas and auto


先前我提到過在 tr1::functions 中存儲 lambda 函數(shù)。但是如非必要請別這么做,因為 tr1::function 會增加一些開銷。如果你想重用 lambda 函數(shù),或只想給它命名的話,你可以使用 auto。這兒有一個簡潔的例子:


C:\Temp>type autolambdakitty.cpp

#include <algorithm>

#include <iostream>

#include <ostream>

#include <vector>

using namespace std;

 

template <typename T, typename Predicate> void keep_if(vector<T>& v, Predicate pred) {

    auto notpred = [&](const T& t) {

        return !pred(t);

    };

 

    v.erase(remove_if(v.begin(), v.end(), notpred), v.end());

}

 

template <typename Container> void print(const Container& c) {

    for_each(c.begin(), c.end(), [](const typename Container::value_type& e) { cout << e << " "; });

    cout << endl;

}

 

int main() {

    vector<int> a;

 

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

        a.push_back(i);

    }

 

    vector<int> b;

 

    for (int i = 100; i < 200; ++i) {

        b.push_back(i);

    }

 

    auto prime = [](const int n) -> bool {

        if (n < 2) {

            return false;

        }

 

        for (int i = 2; i <= n / i; ++i) {

            if (n % i == 0) {

                return false;

            }

        }

 

        return true;

    };

 

    keep_if(a, prime);

    keep_if(b, prime);

 

    print(a);

    print(b);

}

 

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

autolambdakitty.cpp

 

C:\Temp>autolambdakitty

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199


notpred 是一個否定 lambda 函數(shù),注意我們不能使用 C++ 98 <functional>中的 not1() 函數(shù),因為那要求你的謂詞函數(shù)繼承自 unary_function,而 lambda 函數(shù)并不滿足這個條件。


static_assert


static_assert 讓你能夠在觸發(fā)編譯器錯誤時使用定制的錯誤信息:

C:\Temp>type staticfluffykitten.cpp

template <int N> struct Kitten {

    static_assert(N < 2, "Kitten<N> requires N < 2.");

};

 

int main() {

    Kitten<1> peppermint;

 

    Kitten<3> jazz;

}

 

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

staticfluffykitten.cpp

staticfluffykitten.cpp(2) : error C2338: Kitten<N> requires N < 2.

        staticfluffykitten.cpp(8) : see reference to class template instantiation 'Kitten<N>' being compiled

        with

        [

            N=3

        ]


如果你有任何疑問,我很樂意在評論中回答它們。


Stephan T. Lavavej

Visual C++ Libraries Developer

Published Tuesday, October 28, 2008 9:31 AM by vcblog


(轉(zhuǎn)載時請注明作者和出處。未經(jīng)許可,請勿用于商業(yè)用途) 

posted on 2009-05-28 11:27 羅朝輝 閱讀(4759) 評論(14)  編輯 收藏 引用 所屬分類: C/C++

評論

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-28 12:34 Chipset
這點微不足道的特性幾乎可以忽略不說。  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-28 13:25 Etrnls
@Chipset
lambda是微不足道的?  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-28 14:37 尹東斐
恩,你全文翻譯了,敬佩中,這三篇雖然看了,我覺得rvalue reference比較有意思。

當然樓上說這些特性微不足道,是因為他還沒到能看出來這些特性強大之處的境界~~

不過不知道為啥vc10不支持conception,這個鄙人認為是最強大的特性之一了,有了這個,就可以和那種上百KB的error message說再見了。  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-28 14:39 飄飄白云
使用 lambda 的代碼更加簡潔,很少有人愿意單獨去整個函數(shù)對象來使用 for_each  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-28 19:49 playcpp
喜歡C++編程的朋友 請加入QQ群 36071431 有很多人和你一起討論解決問題(還有40個名額) 。  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-28 21:32 bneliao
寫得很清晰,翻譯很流暢,贊。

  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-29 02:02 Pear
微不足道?我的天!當我得知2010支持C++0x的特性時就立刻起了一身雞皮疙瘩了哇  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-30 08:37 dopoco
C++想把事情變簡單點兒,卻把C++本身弄得越來越晦澀難懂,C++就是C++,干嘛非要和JAVA、C#靠齊  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-30 23:28 eXile
lambda是個令人欣喜的特性,至于右值引用,可以極大地提高標準庫的效率,但是對一般的程序員沒有什么太大影響,不好理解的話,就當它不存在好了。  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性:Lambdas,auto,以及 static_assert 2009-05-31 21:39 飄飄白云
總結(jié)下:
lambda 更好地支持函數(shù)式編程
rvalue 提高效率
static_assert 在編譯期間即可 assert 而不再需要等到運行時
auto 可以讓程序員偷點懶,還可以自動類型推導,并且可在編譯期間確定類型
  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性 part 1:Lambdas,auto,以及 static_assert 2009-06-08 01:25 狼狗
@飄飄白云
為何lambda在value capture下可以修改靜態(tài)外部變量?
為何對靜態(tài)變量和非靜態(tài)變量有不同處理策略?
例如:

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

int main()
{
    
static int v = 0;
    
char ch[2009];
    for_each(ch, ch 
+ sizeof(ch), [=](char c) {v++;});
    cout
<<v<<endl; // v=2009
}

.   回復  更多評論
  

# re: 【譯】VC10中的C++0x特性 part 1:Lambdas,auto,以及 static_assert 2009-06-08 10:17 羅朝輝
@狼狗

這是因為是 static 的緣故,static 變量在內(nèi)存中始終都只有一份,它在這里相當于全局的,和非靜態(tài)局部變量有著本質(zhì)不同。  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性 part 1:Lambdas,auto,以及 static_assert 2009-06-09 15:49 狼狗
感覺你沒有回答我的問題啊:為何對靜態(tài)變量和非靜態(tài)變量有不同處理策略?
static變量就不可以在lambda內(nèi)有一個拷貝嗎?明顯是可以的。
那么為何要采用這種使得capture規(guī)則不完美的策略呢?
  回復  更多評論
  

# re: 【譯】VC10中的C++0x特性 part 1:Lambdas,auto,以及 static_assert 2009-06-09 17:06 羅朝輝
@狼狗

我猜是為了保持 static 語義的一致性吧,就如 val 一樣:

void foo()
{
static int val = 0;
val++;

}  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            在线不卡亚洲| 欧美日韩精品一区二区在线播放| 欧美一区二区三区视频在线| 在线观看精品一区| 99精品国产在热久久婷婷| 一区二区三区欧美日韩| 亚洲最新视频在线播放| 亚洲欧洲久久| 亚洲在线中文字幕| 亚洲精品自在在线观看| 一本高清dvd不卡在线观看| 亚洲国产欧美精品| 亚洲色图综合久久| 一区二区三区蜜桃网| 国产亚洲人成a一在线v站| 精品成人久久| 欧美自拍偷拍午夜视频| 久久久91精品国产| 欧美专区在线观看一区| 欧美国产日韩一区二区| 欧美 日韩 国产在线| 一本在线高清不卡dvd| 一区二区三区精品久久久| 在线性视频日韩欧美| 久久精品在这里| 免费日韩av| 欧美午夜不卡视频| 国产日韩精品一区二区三区| 在线观看欧美日韩国产| 亚洲黄色av一区| 夜夜嗨av一区二区三区网页 | 一区二区免费在线视频| 99在线精品视频在线观看| 欧美一区三区二区在线观看| 欧美主播一区二区三区美女 久久精品人| 亚洲国产精品va在线观看黑人 | 日韩午夜精品| 亚洲一区二区三区乱码aⅴ蜜桃女| 亚洲校园激情| 欧美精品色综合| 国产主播一区二区三区| 亚洲大胆人体视频| 亚洲欧美日韩国产中文| 日韩视频在线永久播放| 亚洲精品综合久久中文字幕| 亚洲国产精品久久| 欧美一区免费| 欧美亚洲一区三区| 欧美精品免费在线| 亚洲美女黄网| 久久久天天操| 国产免费成人| 亚洲砖区区免费| 亚洲日本在线视频观看| 久久综合国产精品台湾中文娱乐网| 国产精品久久婷婷六月丁香| 一区二区精品| 亚洲看片一区| 欧美激情视频给我| 亚洲精品国产日韩| 亚洲国产小视频在线观看| 久久久美女艺术照精彩视频福利播放 | 亚洲国产欧美一区二区三区同亚洲| 欧美在线免费播放| 国产精品永久在线| 午夜在线一区| 亚洲一区欧美一区| 国产精品国产三级国产普通话蜜臀| 一区二区电影免费观看| 日韩午夜免费| 国产精品免费观看在线| 亚洲一级高清| 性色av一区二区怡红| 国产精品久久久久久久久久久久| 亚洲一区久久| 夜夜嗨av一区二区三区网站四季av| 宅男噜噜噜66国产日韩在线观看| 欧美国产日韩一区| 国产亚洲欧美日韩在线一区| 亚洲综合色激情五月| 久久免费99精品久久久久久| 久久国产精品亚洲77777| 国产欧美一区二区精品性色| 久久久综合网站| 久久精品成人欧美大片古装| 狠狠久久综合婷婷不卡| 亚洲日本电影在线| 欧美一区二区三区免费观看| 黑人巨大精品欧美一区二区小视频| 欧美mv日韩mv国产网站| 日韩视频亚洲视频| 欧美人与禽性xxxxx杂性| 亚洲黄色天堂| 日韩一级黄色大片| 国产日韩av一区二区| 久久久久青草大香线综合精品| 亚洲欧美日本另类| 欧美日韩在线播放三区| 久久只精品国产| 99视频日韩| 亚洲裸体俱乐部裸体舞表演av| 免费不卡亚洲欧美| 欧美精品一区二区久久婷婷| 亚洲精品日本| 午夜精品久久久久久久99热浪潮| 国产精品久久久99| 久久狠狠婷婷| 欧美日产国产成人免费图片| 亚洲欧美精品| 一本大道久久a久久精品综合| 国产精品一区二区久激情瑜伽| 欧美专区亚洲专区| 欧美插天视频在线播放| 欧美激情国产日韩| 欧美精品一区三区| 亚洲人成绝费网站色www| 午夜精品在线看| 在线看视频不卡| 亚洲欧美国产77777| 亚洲激情小视频| 亚洲一区二区三区四区在线观看| 亚洲精品视频免费| 性欧美xxxx视频在线观看| 一本大道久久精品懂色aⅴ| 亚洲免费在线精品一区| 亚洲欧洲一区二区三区在线观看| 欧美一区1区三区3区公司| 亚洲精品小视频| 亚洲九九精品| 9色精品在线| 久久亚洲国产精品日日av夜夜| 欧美在线视频一区二区| 欧美精品日本| 免费黄网站欧美| 黄色国产精品| 午夜激情久久久| 欧美永久精品| 国产精品久久久亚洲一区| 欧美国产精品va在线观看| 1024日韩| 久久国产精品久久w女人spa| 久久九九热re6这里有精品| 国产精品va在线播放| 欧美日韩一区二区三区在线视频| 国产精品欧美久久| 欧美成人嫩草网站| 在线综合亚洲欧美在线视频| 国产一区二区三区高清| 欧美日韩精品久久久| 久久网站免费| 亚洲欧美日韩中文视频| 亚洲盗摄视频| 久久手机免费观看| 久久久久一区二区三区| 亚洲国产小视频在线观看| 欧美在线观看视频一区二区三区 | 国产丝袜一区二区三区| 亚洲一区二区三区四区五区午夜| 午夜精品久久久久久| 国产精品一页| 99热这里只有精品8| 欧美中文在线观看| 国产精品视频专区| 亚洲一区在线看| 老色鬼精品视频在线观看播放| 国产一区二区成人| 尹人成人综合网| 蜜桃av综合| 性娇小13――14欧美| 久久人人看视频| 韩国成人福利片在线播放| 欧美激情精品久久久久久免费印度| 免费在线日韩av| 欧美一级一区| 欧美国内亚洲| 亚洲九九爱视频| 国产午夜久久| 久久久久久亚洲精品杨幂换脸 | 亚洲电影免费在线| 99国产精品久久久久老师| 欧美中文在线观看国产| 久久综合狠狠| 亚洲一级特黄| 国产老肥熟一区二区三区| 蜜臀久久99精品久久久画质超高清| 亚洲第一网站| 亚洲一区www| 91久久亚洲| 国产精品劲爆视频| 欧美大片在线观看一区| 在线一区二区三区做爰视频网站 | 亚洲国产mv| 亚洲性图久久| 亚洲开发第一视频在线播放| 亚洲欧美日韩国产中文| 亚洲精品国久久99热| 亚洲少妇诱惑| 亚洲一区二区三区免费观看| 欧美成熟视频| 麻豆久久久9性大片|