for each語法是方便的,也是很天然的,這也是爲何不少語言都有這樣的語法,就我所知,包括java(jdk5.0以上),python,php,asp.net等語言都有相似的語法,甚至微軟爲C++/CLI中也添加了這樣的語法。可是很遺憾的是,C++98標準中沒有,因而,咱們只能經過可悲的for_each算法去模擬。。。。。。。。。。先看看原生的語法是多麼方便和天然的吧,雖然有人將其視爲語法糖,可是,就算是糖,這也是很甜的那種。php
先看看Python中的循環,雖然不是for each,可是相似於。java
l = [1,2,3,4,5]python
for i in l:ios
print i程序員
簡潔,乾淨,算法
假如你有幸使用微軟的託管C++,你可使用相似的語法:asp.net
using namespace System;函數
#include <list>spa
#include <iostream>.net
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
for each ( int i in l)
Console::Write(i);
system("PAUSE");
}
雖然做爲強類型語言,在聲明方面稍微複雜點,循環的處理仍是那麼簡潔,乾淨。
再來看看現有的C++中的:
#include <list>
#include <iostream>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
// 一樣是須要輸出
for(list<int>::const_iterator lit = l.begin(); lit != l.end(); ++lit)
{
cout <<*lit <<endl;
}
system("PAUSE");
}
繁複到我都不想說了,list<int>::const_iterator似的迭代器聲明語法不符合一處定義的原則,冗餘信息太多。(C++09添加的auto用法就是解決此問題的),即使是解決了此問題,仍是會發現,在C++中寫個循環比在python(僅僅是一個例子,其餘有相似for each特性的語言都比C++簡單)中複雜太多了。而循環實在是太過於常見的語法了,因此一次又一次使用這種本能夠簡單,可是受限於語法而搞得這麼複雜的C++可憐語法的時候,我老是忍不住想要吐血。對於這麼簡單的例子,咱們是能夠找到一些方法來稍微簡化一點的。沒有for each語法,咱們起碼還有for_each算法-_-!
因而能夠這樣:
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;
void printInt(int i)
{
cout <<i <<endl;
}
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
// 一樣是須要輸出
for_each(l.begin(), l.end(), ptr_fun(printInt));
system("PAUSE");
}
在加大了理解難度後(原本for each語法多簡單啊,如今還要理解ptr_fun這樣的函數對象生成的輔助函數),咱們的循環是稍微簡單一點了,雖然在這個例子中咱們甚至要額外寫函數-_-!雖說函數能夠只寫一次,循環但是經常用的啊。
對於這樣簡單的例子,已經能夠看出沒有for_each語法的痛苦了,再複雜一點的例子
對於類成員函數的調用,看看有for_each的狀況
python中:
class Add():
def __init__(self, i):
self._i = i
def add(self):
self._i += 1
def __str__(self):
return str(self._i)
s = [Add(1), Add(2), Add(3)]
for a in s:
a.add()
for a in s:
print a
這裏拆分紅兩個函數,能夠看出個人無奈,想要在一個for_each語法中連續調用兩個函數的方法。。。。目前只有再寫一個函數,而這個函數的做用就是僅僅調用這兩個函數提供給for_each使用。不說這些喪氣+無奈的話了,光是調用一個類的成員函數的可能仍是有的。
C++中:
#include <list>
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
void printInt(int i)
{
cout <<i <<endl;
}
class CAdd
{
public:
CAdd(int ai):mi(ai) { }
void add() { ++mi; }
operator int() { return mi;}
int mi;
};
int main()
{
CAdd a[3] = { CAdd(1), CAdd(2), CAdd(3)};
list<CAdd> l(a, a+3);
// 一樣是須要輸出
for_each(l.begin(), l.end(), mem_fun_ref(&CAdd::add));
for_each(l.begin(), l.end(), ptr_fun(printInt));
system("PAUSE");
}
爲了實現循環的簡潔,從新引入了新的複雜度,mem_fun_ref,但願通常的C++程序員見過這樣的函數對象輔助函數。。。。還多了相似&CAdd::add這樣的成員函數指針的語法,但願通常的程序員也能理解。。。。(不提有for each語法的語言中除了for each這樣天然的語法外,作多複雜的運算都沒有引入任何新的複雜度),最主要的是,你想要在一條for_each中實現兩個函數的調用,你除了老老實實的實現一個新的函數外,就是像我這樣了,調用for_each兩次,兩種方法都是不那麼容易讓人接受。。。。。。。。可是,在現有的C++中,咱們也就只能作到這樣了。既然用C++,就接受現實吧。其實,顯示遠比通常人想象的要複雜。
以上狀況仍是函數沒有參數的時候,當函數有參數的時候,新的問題又來了。
看看python中這樣一個簡單的功能:
def add(a,b):
return a + b
l = [1,2,3,4,5]
for i in l:
print add(i,1)
無非就是在每一個輸出的函數中調用一個函數,沒有任何值的一提的地方,是我的就能看懂。
在C++須要實現成下面這個樣子:
#include <list>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
template <typename T>
class Add : public binary_function<T, T, void>
{
public:
void operator()(const T& ai, const T& aj) const
{
cout <<(ai + aj) <<endl;
}
};
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
for_each(l.begin(), l.end(), bind2nd(Add<int>(), 1));
system("PAUSE");
}
到這一步,我但願大部分的C++程序員還能看懂什麼意思及其實現的機制。。。。可是僅僅是個人但願吧,甚至我懷疑,這樣的實現放在工做中,總監和老老是不是會將我批的體無完膚,的確,爲了省略一個循環值得這樣作嗎?實在不值得,可是C++提供給你的機制就是這樣。Add這樣的函數對象構造複雜,還得利用trail機制(從binary_function類繼承過來),而後再利用函數適配器bind2nd/bind1st,這樣的東西彷佛須要語言專家來解釋,我是解釋不清楚了,再加上更加複雜的函數連標準庫中的bind都確定不夠用,還只能用boost::bind庫,去試試吧,而後會發現通常的函數指來指去(特別是類成員)用的太複雜了,仍是用boost::funciton吧。。。。。彷佛永無止境。可是有了for each語法,那麼什麼複雜度都沒有。。。。。還想自虐嗎?算了吧,我基本上已經放棄了。不給糖吃,也放不着本身開工廠製做。。。。
另外,對於可以用boost的兄弟們,糖是有的吃的。boost:: foreach庫便是如此。
下面是boost:: foreach的例子
#include <list>
#include <iostream>
#include <boost/foreach.hpp>
using namespace std;
int main()
{
int a[5] = {1,2,3,4,5};
list<int> l(a, a+5);
BOOST_FOREACH( int i, l)
{
cout <<i <<endl;
}
BOOST_FOREACH( int i, l)
{
cout <<i+1 <<endl;
}
system("PAUSE");
}
就算僅僅這一個例子。。。。永遠不要怪庫開發者(好比boost,ace,loki)將C++語言弄得多麼扭曲,他們也是出於無奈。。。。別去看實現,先只管用吧。
對於不能用boost的我。。。。只能看有沒有辦法偷偷的將/cli編譯選項打開了。。。^^