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

李錦俊(mybios)的blog

游戲開發(fā) C++ Cocos2d-x OpenGL DirectX 數(shù)學(xué) 計算機圖形學(xué) SQL Server

  C++博客 :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
  86 Posts :: 0 Stories :: 370 Comments :: 0 Trackbacks

公告

QQ:30743734
EMain:mybios@qq.com

常用鏈接

留言簿(16)

我參與的團隊

最新隨筆

搜索

  •  

積分與排名

  • 積分 - 373511
  • 排名 - 67

最新評論

閱讀排行榜

評論排行榜

從 STL 出現(xiàn)到現(xiàn)在已經(jīng)這么多年了,泛型算法是它的重要組成,也是其中最“看起來很美”的東西之一。然而在真實的程序設(shè)計中,它往往成為程序員的心頭一痛,因為一旦要用 for_each ,accumulate 之類的算法做一些稍微復(fù)雜一點的事情,你就會發(fā)現(xiàn)自己一個頭變成兩個大。

從 STL 出現(xiàn)到現(xiàn)在已經(jīng)這么多年了,泛型算法是它的重要組成,也是其中最“看起來很美”的東西之一。然而在真實的程序設(shè)計中,它往往成為程序員的心頭一痛,因為一旦要用 for_each ,accumulate 之類的算法做一些稍微復(fù)雜一點的事情,你就會發(fā)現(xiàn)自己一個頭變成兩個大。即便是有了 boost::bind 和 boost.lambda 的幫助,事情也仍然是撲朔迷離,求助于 comp.lang.c++ 雖然有用,但是又何嘗不是一種無奈。好了,現(xiàn)在我開始收集一些來自 comp.lang.c++(.moderated) 的解答,希望日后對自己和他人有用。

=================================================================================

預(yù)備問題(算是第0個問題吧):如何對一個 STL 容器內(nèi)的所有元素做某件事情?

這取決于你要做什么,以及容器是什么。如果是 vector, list 這樣的容器,而你要把它們?nèi)?cout 出來,當(dāng)前的標(biāo)準(zhǔn) STL 解法是這樣的:

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
#include <string>

int main()
{
? std::vector<std::string> vect;
? vect.push_back("Hello");
? vect.push_back(", ");
? vect.push_back("world!");
?
? std::copy( vect.begin(), vect.end(),
??? std::ostream_iterator<std::string>(std::cout) );
}

基本上,這算是一個“過得去”的方案,但是有點問題:
1. 對于不熟悉這個固定用法的人,cout 所有元素所首要考慮算法是 for_each,而不是 copy ,事實上,for_each 也是最符合我們慣常邏輯的算法,因為在不使用 STL 算法的時候,我們使用 for 循環(huán)來干這件事。
2. 可讀性不太良好,ostream_iterator 的使用有點 tricky ,而且也不能用于做其他的事情。

我想熟悉 boost? 的人已經(jīng)知道我下面要說什么了,因為用 boost.lambda 做這件事情的確非常漂亮:

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;

int main()
{
? std::vector<std::string> vect;
? vect.push_back("Hello");
? vect.push_back(", ");
? vect.push_back("world!");
?
? std::for_each( vect.begin(), vect.end(), std::cout << _1 );
}

這和前面的程序一樣,輸出我們熟悉的 Hello, world! 。直觀、優(yōu)雅而且容易修改,例如,如果你不是想要輸出它們的值,而是想要輸出它們的長度,只需要做很少的修改:

std::for_each( vect.begin(), vect.end(), std::cout << bind(&std::string::length, _1) << "\n" );

輸出
5
2
6

bind 的作用是把 lambda 表達式綁定到一個函數(shù)或者一個數(shù)據(jù)成員,在這里的意思,就是對于每一個 string ,都調(diào)用其 length() 方法。_1 同樣也可以成為賦值的對象,例如,先執(zhí)行

std::for_each( vect[0].begin(), vect[0].end(), _1 = bind(&toupper, _1) );

然后再把這些 string 輸出,你會得到

HELLO, world!

因為那一句對 "Hello" 中的每一個字母調(diào)用 toupper ,并把結(jié)果寫回。

=================================================================================

第一個問題:如何對一個 map 中所有的 key 或者 value 做某件事情?

當(dāng)然,這還是取決于你要做的是什么。手寫 for 循環(huán)當(dāng)然是萬能的,但是現(xiàn)在有了那么多的泛型算法,我們可以考慮其他的方案了(這也是眾多 C++ Gurus 推薦的思維方式)如果是把所有的 value 全部 cout 出來,用 boost.lambda 配合 for_each 還是比較優(yōu)雅的(雖然沒有像 vector 和 list 那樣的優(yōu)雅):

#include <iostream>
#include <algorithm>
#include <map>
#include <string>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;

int main()
{
? std::map<int, std::string> strs;
? strs[0] = "Hello";
? strs[1] = ", ";
? strs[2] = "world";
? strs[3] = "!";
?
? std::for_each( strs.begin(), strs.end(),
??? std::cout << bind(&std::map<int, std::string>::value_type::second, _1) );
}

這樣的輸出如我們所料,就是 Hello, world!

如果想要把 key 也輸出,道理是一樣的,只需要這樣:

? std::for_each( strs.begin(), strs.end(),
??? std::cout << bind(&std::map<int, std::string>::value_type::second, _1) << '\t'
??????????????????? << bind(&std::map<int, std::string>::value_type::first, _1) << '\n'
? );

其結(jié)果是:

Hello?? 0
,??????????? 1
world?? 2
!??????????? 3

因此,對于一個 map 中的 value 的操作往往可以依法炮制,如果我們想要在其中尋找 value 為 “world" 的那一個元素,并且輸出它的 key ,只需要一句話:

? std::cout <<
??? std::find_if( strs.begin(), strs.end(),
????? bind(&std::map<int, std::string>::value_type::second, _1) == "world" )->first;

STL 算法 find_if 接受的第三個參數(shù)是一個 prediate ,而生成這種臨時的 functor 正是 lambda 的拿手好戲。上面的這句話也可以用 boost::bind 來做,只需要更改 include 和 using namespace ,代碼本身無需更改。而如果你不借助于它們,你只有手寫循環(huán)或者自己寫一個 predicate 。

當(dāng)情況變得復(fù)雜一些的時候,lambda 的用法也變得更加有趣了:

#include <iostream>
#include <algorithm>
#include <map>
#include <string>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;

class Person
{
public:
? Person(){}
? Person(const std::string& name) : name_(name){}
?
? std::string Name()
? { return name_; }
?
private:
? std::string name_;
};

int main()
{
? std::map<int, Person> persons;
? persons[123] = Person("Amy");
? persons[234] = Person("Ralph");
? persons[345] = Person("Simon");
? persons[456] = Person("Maggie");

? std::for_each( persons.begin(), persons.end(),
??? std::cout << bind(&std::map<int, Person>::value_type::first, _1) << '\t'
??????????????????? << bind(&Person::Name,
??????????????????????????? bind(&std::map<int, Person>::value_type::second, _1)) << '\n'
? );

? std::cout << "Ralph's Id is: " <<
??? std::find_if( persons.begin(), persons.end(),
????? bind(&Person::Name,
??????? bind(&std::map<int, Person>::value_type::second, _1)) == "Ralph" )->first;
}

這里 map 的 value 元素不再是一個單純的 string,我們要輸出的是這個 value 的 Name() ,幸好 lambda 的綁定可以級聯(lián),所以我們?nèi)匀豢梢杂?STL 算法在一個表達式之內(nèi)搞定這些任務(wù):for_each 輸出 key 和 value 的 Name(),而 find_if 找到 value 的 Name() 為 "Ralph" 的那一個元素,輸出是這樣的:

123???? Amy
234???? Ralph
345???? Simon
456???? Maggie
Ralph's Id is: 234



如果你想要把一個容器內(nèi)的所有元素累加起來,應(yīng)該怎么辦?

如果你想要把一個容器內(nèi)的所有元素累加起來,應(yīng)該怎么辦?

STL 的 accumulate 可以讓我們不必自己寫循環(huán):

#include <iostream>
#include <functional>
#include <numeric>
#include <vector>
#include <string>

int main()
{
? std::vector<int> vect;
? vect.push_back(1);
? vect.push_back(2);
? vect.push_back(3);
? vect.push_back(4);
?
? std::cout << "Accumulate: " <<
??? std::accumulate( vect.begin(), vect.end(), 0, std::plus<int>());
}

輸出:

Accumulate: 10

其中的 std::plus<int>() 可以省略,因為這將是3個參數(shù)的 accumulate 的默認行為。 注意 accumulate 算法是定義在 numeric 里面而不是 algorithm 里面的。

由于 accumulate 和 plus 都是泛型的,所以如果你要累加的不是 int 而是字符串,對程序的修改也并不大:

#include <iostream>
#include <functional>
#include <numeric>
#include <vector>
#include <string>

int main()
{
? std::vector<std::string> vect;
? vect.push_back("1");
? vect.push_back("2");
? vect.push_back("3");
? vect.push_back("4");
?
? std::cout << "Accumulate: " <<
??? std::accumulate( vect.begin(), vect.end(), std::string(""));
}

輸出:
Accumulate: 1234

不過,如果使用 boost.lambda ,這個問題會有一些很好看又容易理解的解法:

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <string>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
//#include <boost/bind.hpp>

using namespace boost::lambda;
//using namespace boost;

int main()
{
? std::vector<std::string> vect;
? vect.push_back("1");
? vect.push_back("2");
? vect.push_back("3");
? vect.push_back("4");
?
? std::string result;
?
? std::for_each( vect.begin(), vect.end(), result += _1);
?
? std::cout << result;
}

輸出:
1234

這里要借用變量 result ,在這個程序中顯得多了幾行,但是我們調(diào)用 accumulate 的目的也往往是把結(jié)果放到一個變量中,這樣的話,使用 boost.lambda 反而會漂亮一些。

在上面的程序中,另一個丑陋的地方就是 vector 的初始化,為了把 1, 2, 3, 4 放進 vect 里面,我們居然要調(diào)用 push_back 4次!不過,使用 boost.lambda 就好得多了。

? std::vector<int> vect(10);
? int i = 0;
? std::for_each( vect.begin(), vect.end(), _1 = ++var(i) );

這里有兩個地方值得注意:
1. 現(xiàn)在必須在 vect 的聲明中指出其大小,否則 for_each 對一個空容器可是什么也不會做
2. 必須使用 ++var(i) ,而不是 ++i 。var 在這里的作用是強迫 lazy evaluation ,也就是讓變量在被用到的時候在求值,如果用 ++i ,你會得到一個裝有10個1的 vect ,而不是裝有1-10。

=================================================================================

許多問題遇到 map 都會變得復(fù)雜起來,如果想要把一個 map 中所有的 key 或者 value 累加起來,該怎么辦呢?這個時候已經(jīng)不能直接使用 accumulate 了,用 boost.bind 可以辦到,做法是這樣的:

#include <iostream>
#include <algorithm>
#include <numeric>
#include <map>
#include <string>

#include <boost/bind.hpp>

using namespace boost;

int main()
{
? std::map<int, std::string> persons;
? persons[123] = "Amy";
? persons[234] = "Ralph";
? persons[345] = "Simon";
? persons[456] = "Maggie";
?
? std::cout << std::accumulate( persons.begin(), persons.end(), 0,
??? bind(std::plus<int>(), _1, bind(&std::map<int, std::string>::value_type::first, _2)) )
??? << std::endl;

? std::cout << std::accumulate( persons.begin(), persons.end(), std::string(),
??? bind(std::plus<std::string>(), _1, bind(&std::map<int, std::string>::value_type::second, _2)) )
??? << std::endl;
}

輸出:

1158
AmyRalphSimonMaggie

辦是辦到了,但是平心而論,的確算不上是漂亮。連續(xù)的 bind 并不比自己寫的循環(huán)更讓人頭暈。boost.lambda 也要用到 bind ,然而可以清晰許多:

#include <iostream>
#include <algorithm>
#include <numeric>
#include <map>
#include <string>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;

int main()
{
? std::map<int, std::string> persons;
? persons[123] = "Amy";
? persons[234] = "Ralph";
? persons[345] = "Simon";
? persons[456] = "Maggie";

? int iresult = 0;
? std::string sresult;
?
? std::for_each( persons.begin(), persons.end(),
??? iresult += bind(&std::map<int, std::string>::value_type::first, _1)
? );
?
? std::for_each( persons.begin(), persons.end(),
??? sresult += bind(&std::map<int, std::string>::value_type::second, _1)
? );
?
? std::cout << iresult << std::endl;
? std::cout << sresult << std::endl;
}

輸出和上面的一樣:

1158
AmyRalphSimonMaggie

有了它的幫助,即便間接層次再增加一層,也不會有太多困難:假如你的 map 并不直接存儲 string ,而是存儲 Person 對象,而它們的名字要通過 Name() 方法來取得,代碼只需要稍微的修改:


#include <iostream>
#include <algorithm>
#include <numeric>
#include <map>
#include <string>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;

class Person
{
public:
? Person(){}
? Person(const std::string& name) : name_(name){}
?
? std::string& Name()
? { return name_; }
?
private:
? std::string name_;
};

int main()
{
? std::map<int, Person> persons;
? persons[123] = Person("Amy");
? persons[234] = Person("Ralph");
? persons[345] = Person("Simon");
? persons[456] = Person("Maggie");

? std::string result;
?
? std::for_each( persons.begin(), persons.end(),
??? result += bind(&Person::Name, bind(&std::map<int, Person>::value_type::second, _1))
? );
?
? std::cout << result;
}

輸出:

AmyRalphSimonMaggie






上次提到過為容器生成數(shù)據(jù)的問題,我給出的用 boost.lambda 的方法是

上次提到過為容器生成數(shù)據(jù)的問題,我給出的用 boost.lambda 的方法是:

? std::vector<int> vect(10);
? int i = 0;
? std::for_each( vect.begin(), vect.end(), _1 = ++var(i) );

不錯,這樣可以生成連續(xù)的數(shù)字,也還算比較簡潔,因為代碼量不會隨著容器的大小而變化,不過,如果要在容器內(nèi)填入隨機數(shù)呢?其實比上面更簡單,因為 STL 的 generate 算法就是設(shè)計來做這個的:

? std::vector<int> vect(10);
? std::generate(vect.begin(), vect.end(), rand);

rand 是我們熟悉的標(biāo)準(zhǔn) C 庫函數(shù),這樣我們可以生成任意數(shù)量的隨機數(shù)了,不過還是有點不好的地方:每次生成的序列都是一樣的,因為 rand 生成的是偽隨機數(shù)。這個容易解決,我們必須先 seed 一下:

? std::vector<int> vect(10);
? srand(time(NULL));
? std::generate(vect.begin(), vect.end(), rand);

好了,我們終于還是用了三行(其實是兩行,聲明 vector 總是必需的吧!),但是好歹是有了一個可用的方案。回頭看看,前面的連續(xù)整數(shù)問題也可以用 generate 來做,方法不言而喻:

? std::vector<int> vect(10);
? int i = 0;
? std::generate(vect.begin(), vect.end(), ++var(i));

好處是 generate 本身更能說明這句話的用途,當(dāng)然這個可能因人而異。

我知道有人一定在問:一定要兩行么?一定要有一個初始變量么?答案是可以沒有,但是要用到另外的算法,再加上 boost.lambda 的協(xié)助。看看下面:

? std::vector<int> vect(10);
? std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = _1 + 1);

如果你現(xiàn)在把 vect 輸出,你會得到:

0 1 2 3 4 5 6 7 8 9

乍看起來不太好理解,我來慢慢解釋。
partial_sum 的第4個參數(shù)是一個雙參數(shù)的 functor ,在這里,lambda 表達式 _2 = _1 + 1 充當(dāng)了這個角色,它相當(dāng)于

f(x, y)? {? y? =? x? +? 1;? }

而 partial_sum 呢?它把一個序列的 partial sum 送到結(jié)果序列中去,例如如果輸入一個數(shù)組 v[10] ,而輸出是 r[10] ,那么它的計算就是

r[0] = v[0]????????????
r[1] = f( r[0], r[1] )
r[2] = f( r[1], r[2] )
......
r[9] = f( r[8], r[9] )

而當(dāng)我們把 partial_sum 作用于 vect 本身,結(jié)果就成了

vect[0] = vect[0]??????????????????????????? // vect[0] = 0
vect[1] = (vect[1] = vect[0] + 1)?? // vect[1] = 1
vect[2] = (vect[2] = vect[1] + 1)?? // vect[2] = 2
......
vect[9] = (vect[9] = vect[8] + 1)?? // vect[9] = 9

你一定發(fā)現(xiàn)其中的問題所在了:首先,我們必須依賴于編譯器把 vect[0] 初始化為0,其次,vect[0] = vect[0] 是不可回避的。以我當(dāng)前所想到的,也只能這樣了。

推廣一下,如果把
_2 = _1 + 1 中的常數(shù) 1 換成另外的數(shù)字,我們就可以用一句話得到從 0 開始的等差數(shù)列,例如

? std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = _1 + 3);

得到的是

0 3 6 9 12 15 18 21 24 27

如果再發(fā)揮一點想象力,你就可以構(gòu)造出更復(fù)雜的 lambda 表達式,從而得到更復(fù)雜的數(shù)組(也許這里叫數(shù)列更好吧),例如

? std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = 2 * _1 + 1);

得到的是 2 的 n 次方 - 1 數(shù)列

0 1 3 7 15 31 63 127 255 511

在 STL 算法中,adjacent_difference 和 partial_sum 是逆運算,因此,上面的事情也可以用 adjacent_difference 來做,只不過要把 lambda 表達式中的參數(shù)位置換一下,例如要得到 0, 3, 6... 的等差數(shù)列,只需要

? std::adjacent_difference(vect.begin(), vect.end(), vect.begin(), _1 = _2 + 3);

而 2 的 n 次方 - 1 數(shù)列也是同樣道理

? std::adjacent_difference(vect.begin(), vect.end(), vect.begin(), _1 = 2*_2 + 1);

如果你要生成倒序的數(shù)列呢?當(dāng)然,STL 算法 reverse 可以派上用場,不過也不要忘了 STL 還有 reverse_iterator 這回事,用它就無需另外調(diào)用 reverse 了:

? std::partial_sum(vect.rbegin(), vect.rend(), vect.rbegin(), _2 = 2*_1 + 1);

得到

511 255 127 63 31 15 7 3 1 0

最后還要提醒大家不要忘了一個很有用的 STL 算法: random_shuffle 。它可以把 Random access container 里面的值打亂,配合上面的數(shù)列生成,在很多場合是進行測試
(例如測試排序算法) 的好工具。在我的機器上,下面兩行

? std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = 2*_1 + 1);
? std::random_shuffle(vect.begin(), vect.end());

得到打亂以后的數(shù)列:

255 1 511 3 0 31 127 7 15 63

=================================================================================

有了強大的生成機制作基礎(chǔ),下面的實驗也更加容易了。STL 的 count_if 和 find_if 都接受一個 predicate 作為比較的依據(jù),而這個 predicate 往往非常簡單,以至于為它專門寫一個 functor 簡直不可接受。在第一篇里面已經(jīng)展示了用 boost.lambda 生成臨時的無名 functor 的能力,這里再多說一點。

下面先生成 2^n - 1 的數(shù)組,然后找出其中第一個大于100的數(shù)

? std::vector<int> vect(10);
? std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = 2*_1 + 1);
?
? std::cout << *std::find_if(vect.begin(), vect.end(), _1 > 100);

輸出為 127 ,如我們所料。同樣道理,如果是 count_if ,則會得到大于100的數(shù)的個數(shù)

? std::cout << std::count_if(vect.begin(), vect.end(), _1 > 100);

輸出是 3 。注意細節(jié):find_if 返回一個 iterator ,所以在它之前有 * 解引用,而 count_if 直接返回一個數(shù)字,無需解引用。

與之類似的還有 STL 的 partition 算法,它根據(jù)傳入的 predicate 對一個序列進行劃分,predicate 得到 true 的將放在前面,其余的放在后面,返回的是那些“
放在 后面”的元素中的第一個,換言之就是分界點。下面的代碼

? std::vector<int> vect(10);
? std::partial_sum(vect.begin(), vect.end(), vect.begin(), _2 = 2*_1 + 1);
?
? std::cout << *std::partition(vect.begin(), vect.end(), _1 > 100) << std::endl;
?
? std::for_each(vect.begin(), vect.end(), std::cout << _1 << " ");

輸出為

7
511 255 127 7 15 31 63 3 1 0

如果仔細觀察,還可以發(fā)現(xiàn)上面的輸出有點問題:數(shù)列中原有的順序(0, 1, 3, 7...)不復(fù)存在,這是因為 partition 并不是一個穩(wěn)定排序的算法,它不保證排序結(jié)果保有原來的順序。如果需要穩(wěn)定排序,可以使用 stable_partition 。只需要更改排序的那一句代碼為

? std::cout << *std::stable_partition(vect.begin(), vect.end(), _1 > 100) << std::endl;

結(jié)果是

0
127 255 511 0 1 3 7 15 31 63

當(dāng)然,如果你還記得大學(xué)里的算法理論,就知道它們在效率上是有點區(qū)別的,partition 的復(fù)雜度保證為 O(n) ,具體地說是保證不超過 n/2 次交換;而 stable_partition 在最好情況下為 O(n) ,最差情況則達到 O(n*log(n)) 。

順便說一下,上面的幾件簡單的事情,用標(biāo)準(zhǔn)的 STL 算法都可以辦到,只不過實在是……面目可憎:

? std::cout << *std::partition(vect.begin(), vect.end(),
??? std::bind2nd(std::greater<int>(), 100)) << std::endl;

這句代碼做的事情和前面的 partition 一模一樣,但是孰優(yōu)孰劣,大家自有公斷。


總有一些時候,我們不能夠借助于“生成式”的初始化方法來給容器賦值,例如我們已經(jīng)有了一個數(shù)組,要把它作為初值賦給一個容器,常規(guī)的做法已經(jīng)深入人心了

總有一些時候,我們不能夠借助于“生成式”的初始化方法來給容器賦值,例如我們已經(jīng)有了一個數(shù)組,要把它作為初值賦給一個容器,常規(guī)的做法已經(jīng)深入人心了:

? int init[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
? std::vector<int> vect(init, init + sizeof(init)/sizeof(int));

通過兩個 sizeof 來得到數(shù)組的大小在 C 語言里面是很常見的,然而在 C++ 里面,這即便不能稱為丑陋,也絕對稱不上是好。首先其可讀性不好,其次它要進行一次除法來得到一個本來在編譯期間就知道的數(shù)字,最后,它并不是總能用的!例如下面的例子:

? std::string strs[] = { "Amy", "Ralph", "Simon", "Maggie" };

現(xiàn)在,你打算用 "sizeof " 什么來除以 "sizeof" 什么?

其實,經(jīng)過了這么多 C++ GP 的磨練,我們很容易就會想到一個在編譯期間得到靜態(tài)數(shù)組大小的辦法,模板偏特化是我們常用的武器,在這里非常好用:

template <class T>
struct ArraySize
{
??? static const unsigned int value = 0;
};

template <class T, int S>
struct ArraySize<T[S]>
{
??? static const unsigned int value = S;
};

就這么簡單!雖然它只對付一維數(shù)組,但是擴展它是很容易的。不過,模板參數(shù)只能為類型,而我們需要傳入的是一個變量。好在在計算機科學(xué)里面,加一層抽象是可以解決任何問題的,我們只要加一個模板函數(shù),C++ 會自動幫我們做類型推導(dǎo):

template <class T>
unsigned int array_size(const T&)
{
??? return ArraySize<T>::value;
}

現(xiàn)在我們可以輕而易舉的搞定那些數(shù)組了:

? int ints[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
? std::vector<int> vint(ints, ints + array_size(ints));
?
? std::string strs[] = { "Amy", "Ralph", "Simon", "Maggie" };
? std::vector<std::string> vstr(strs, strs + array_size(strs));
?
? std::for_each(vint.begin(), vint.end(), std::cout << _1 << " ");
? std::cout << std::endl;
? std::for_each(vstr.begin(), vstr.end(), std::cout << _1 << " ");

輸出:

2 3 5 7 11 13 17 19 23
Amy Ralph Simon Maggie

順便說一下,在 boost.type_traits 里面有一個類似于 ArraySize 的工具,叫做 extent ,它更加強大,可以對付多維數(shù)組,不過是否值得為了這個而把 boost.type_traits 包含到工程里面去就看讀者自己抉擇了。

=================================================================================

容器的初始化是如此的常見,以至于 boost 提供了一個 assign 庫來簡化這些操作。boost.assign 大量利用了重載的逗號和括號來簡化賦值操作,提供了甚至比用數(shù)組更加簡潔的語法:

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>

#include <boost/assign/std/vector.hpp>
#include <boost/assign/std/list.hpp>

using namespace boost::assign;

int main()
{
? std::vector<int> vint;
? vint += 2,3,5,7,11,13,17,19,23;
?
? std::vector<std::string> vstr;
? vstr += "Amy","Ralph","Simon","Maggie";
?
? std::list<std::string> lstr;
? lstr += "Amy","Ralph","Simon","Maggie";
???
? std::for_each(vint.begin(), vint.end(), std::cout << _1 << " ");
? std::cout << std::endl;
? std::for_each(vstr.begin(), vstr.end(), std::cout << _1 << " ");
? std::cout << std::endl;
? std::for_each(lstr.begin(), lstr.end(), std::cout << _1 << " ");
}


運行這個程序,輸出與前面的大致相同,但是我們注意到初始化更加簡潔了,而且也不需要額外的空間來存儲數(shù)組,對于各種類型,都能夠以統(tǒng)一的方式來初始化,真是妙不可言。有趣的是 assign 的作者在文檔中還特意引用了 Bjarne Stroustrup 的話作為引子:

There appear to be few practical uses of operator,().
Bjarne Stroustrup, The Design and Evolution of C++

這也許就是 C++ 最大的魅力之一:你無法預(yù)料它可以辦到些什么。

下面關(guān)于 map 的例子也使用 boost.assign ,可以看到重載的括號給我們帶來了多少方便。

#include <iostream>
#include <algorithm>
#include <map>
#include <string>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

#include <boost/assign/list_inserter.hpp>
#include <boost/assign/list_of.hpp>

using namespace std;
using namespace boost::assign;
using namespace boost::lambda;

int main()
{
? map<string,int> months;?
?
? insert( months )
??? ( "january",?? 31 )( "february", 28 )
??? ( "march",???? 31 )( "april",??? 30 )
??? ( "may",?????? 31 )( "june",???? 30 )
??? ( "july",????? 31 )( "august",?? 31 )
??? ( "september", 30 )( "october",? 31 )
??? ( "november",? 30 )( "december", 31 );
???
? map<int,string> persons = map_list_of
??? (2,"Amy")(3,"Ralph")
??? (5,"Simon")(7,"Maggie");
???
? for_each( months.begin(), months.end(),
??? cout << bind(&map<string,int>::value_type::second, _1) << "\t"
???????? << bind(&map<string,int>::value_type::first, _1) << "\n"
? );
? cout << endl;
? for_each( persons.begin(), persons.end(),
??? cout << bind(&map<int,string>::value_type::first, _1) << "\t"
???????? << bind(&map<int,string>::value_type::second, _1) << "\n"
? );?
}

輸出:

30????? april
31????? august
31????? december
28????? february
31????? january
31????? july
30????? june
31????? march
31????? may
30????? november
31????? october
30????? september

2?????? Amy
3?????? Ralph
5?????? Simon
7?????? Maggie


posted on 2006-11-18 09:17 李錦俊(mybios) 閱讀(1640) 評論(2)  編輯 收藏 引用 所屬分類: C++

Feedback

# re: 【轉(zhuǎn)貼】泛型算法:Tips 2007-07-19 09:35 motioo
不錯,不錯。謝謝。  回復(fù)  更多評論
  

# re: 【轉(zhuǎn)貼】泛型算法:Tips 2008-10-15 20:21 ...
非常經(jīng)典的資源!十分感謝樓主!!!我直接整個網(wǎng)頁都下載了.  回復(fù)  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            欧美成人免费播放| 国产在线一区二区三区四区| 日韩一级在线观看| 亚洲国产高清自拍| 嫩草成人www欧美| 美女视频黄a大片欧美| 久久福利精品| 久久久伊人欧美| 欧美国产日韩一区| 亚洲精品中文字幕在线| aa级大片欧美三级| 亚洲一区二区影院| 欧美一区二区大片| 欧美在线观看一二区| 免费看精品久久片| 国产精品v片在线观看不卡 | 久久综合久久综合久久综合| 欧美成人综合| 亚洲最新中文字幕| 久久久精品tv| 欧美视频国产精品| 极品日韩久久| 亚洲一区二区三区乱码aⅴ蜜桃女| 午夜国产精品视频| 欧美电影专区| 午夜精品久久久久久久久久久| 久久激情五月婷婷| 欧美视频一区二区三区四区| 在线观看欧美| 午夜久久久久久| 欧美大胆成人| 午夜性色一区二区三区免费视频| 欧美不卡视频一区发布| 国产欧美在线看| 亚洲黄色在线看| 久久精品91| 夜夜嗨av一区二区三区四区| 久久久91精品国产一区二区精品| 欧美色图首页| 亚洲乱码日产精品bd| 一区二区三区在线免费播放| 欧美美女bb生活片| 国产精品久久久久免费a∨| 国产精品久久久久久av福利软件| 亚洲一区精品电影| 欧美电影在线免费观看网站| 91久久久亚洲精品| 欧美日本一道本| 欧美精品激情| 国产精品扒开腿爽爽爽视频 | 久久综合九色综合久99| 国产一区二区丝袜高跟鞋图片| 欧美视频在线观看视频极品| 女女同性精品视频| 国产欧美激情| 一本到12不卡视频在线dvd| 在线视频日韩| 欧美激情一区二区三区高清视频| 亚洲一区二区三区四区五区黄| 欧美日韩高清在线| 欧美日韩高清在线播放| 亚洲最新视频在线| 久久综合给合久久狠狠狠97色69| 亚洲国产成人在线| av不卡在线| 韩日欧美一区二区| 亚洲图片在线| 男人的天堂亚洲在线| 欧美激情综合网| 99在线精品视频| 久久精品国产精品亚洲综合| 亚洲第一在线| 午夜精品久久久久久久99热浪潮| 在线性视频日韩欧美| 亚洲女性裸体视频| 日韩一区二区精品| 欧美一区二区视频在线观看2020| 欧美亚洲午夜视频在线观看| 1204国产成人精品视频| 亚洲第一福利社区| 久久女同互慰一区二区三区| 国产精品v欧美精品v日韩 | 欧美淫片网站| 欧美在线视频全部完| 国产日韩欧美中文在线播放| 亚洲狼人综合| 国产精品视频自拍| 国产精品vvv| 亚洲欧美制服另类日韩| 亚洲性图久久| 国产日本欧美视频| 久久一本综合频道| 欧美成人久久| 亚洲蜜桃精久久久久久久| 9l国产精品久久久久麻豆| 亚洲美女区一区| 一区二区三区视频在线观看| 国产精品豆花视频| 久久久久久久激情视频| 欧美成年人视频| 国产精品一级二级三级| 久久精品毛片| 欧美精品一区二区三区很污很色的| 一区二区电影免费观看| 亚洲一区欧美二区| 亚洲欧洲精品一区二区三区波多野1战4 | 中文国产一区| 国产一区二区久久久| 亚洲福利av| 国产精品国产三级国产专播品爱网| 久久亚洲一区二区| 国产精品videossex久久发布| 欧美一区二区三区在线看| 久久亚洲影院| 欧美日韩一区二区在线播放| 在线看日韩av| 亚洲午夜一区| 99re热精品| 久久久久久9| 午夜精品婷婷| 欧美日韩亚洲另类| 欧美激情第1页| 激情小说亚洲一区| 亚洲欧美成人在线| 亚洲一区二区在线| 欧美韩国在线| 欧美激情片在线观看| 宅男66日本亚洲欧美视频| 毛片av中文字幕一区二区| 午夜精品久久99蜜桃的功能介绍| 久久久久欧美精品| 久久九九久精品国产免费直播| 欧美日韩黄色大片| 亚洲第一在线视频| 亚洲国产91| 久久在线免费| 欧美丰满少妇xxxbbb| 樱花yy私人影院亚洲| 久久av免费一区| 久热国产精品| 亚洲国产午夜| 欧美xx69| 亚洲国产一区二区a毛片| 亚洲人成网在线播放| 嫩草国产精品入口| 欧美国产日韩一区二区在线观看| 在线成人免费观看| 久久天堂av综合合色| 男人的天堂亚洲在线| 91久久精品国产91性色tv| 欧美成人精品h版在线观看| 欧美国产精品一区| 一本色道88久久加勒比精品| 欧美极品色图| 一区二区日韩欧美| 午夜亚洲福利| 激情久久久久久| 久久久最新网址| 91久久精品国产91久久性色| 一区二区黄色| 国产精品一国产精品k频道56| 亚洲欧美成人一区二区三区| 久久夜色精品国产| 亚洲精品日日夜夜| 国产精品电影在线观看| 午夜精品久久一牛影视| 久久综合影视| 日韩视频在线观看免费| 国产精品久久一卡二卡| 久久精品一区蜜桃臀影院| 亚洲国产一区视频| 亚洲欧美激情诱惑| 在线成人www免费观看视频| 欧美日韩精品在线| 先锋影音国产精品| 欧美高清视频免费观看| 亚洲一区尤物| 亚洲第一精品在线| 欧美日韩国产精品自在自线| 亚洲在线播放| 欧美激情中文字幕一区二区| 日韩视频中文| 亚洲欧洲日本mm| 久久精品国产久精国产思思| 亚洲欧美日韩天堂| 一区二区三区自拍| 欧美日韩成人一区二区| 中文一区二区| 久久综合九色| 免费一级欧美片在线播放| 久久影视三级福利片| 欧美风情在线| 亚洲第一视频网站| 国产日本欧美一区二区三区在线 | 亚洲国产精品一区二区www| 亚洲女人小视频在线观看| 亚洲精品极品| 亚洲电影视频在线| 国产视频精品网| 国产精品白丝av嫩草影院|