一直在使用C/C++,對于循環(huán)語句while、do while、for,對于for情有獨(dú)鐘,因?yàn)槠浜啙崱⑶逦㈧`活。訪問數(shù)組類型的變量,只有for寫出來的語句是最易于閱讀的,如:
int arr[N] = {/*
*/};
for(int i = 0; i < N; ++i)
printf("arr[%d] = %d\n", i, arr[i]);
然而,這種情況,到了STL時(shí),就有些變味了:
for(vector<MyClass>::const_iterator iter = m_vecData.begin(); iter != m_vecData.end(); ++iter)
{
if(!iter->IsBusy())
iter->DoSomeThing(param);
}
這么長的一個(gè)for,不再給人一種清晰的感覺了。或許因?yàn)檫@個(gè)程序比較短,還沒有太大的感覺,當(dāng)回頭去看自已的程序中,有不少這樣的寫法時(shí),我就覺得一陣心煩。改改?
for(size_t i = 0; i < m_vecData.size(); ++i)
{
if(!m_vecData[i].IsBusy())
m_vecData[i].DoSomeThing(param);
}
不錯(cuò),還是簡單點(diǎn)好啊。但是因?yàn)檫@里舉的是vector的例子。如果是list或是別的什么容器,就行不通了。
其它的高級語言,都提供了foreach或是for in語句,寫出來就很清晰:
foreach(item in m_vecData)
{
if(!item.IsBusy())
item.DoSomeThing(param);
}
C++是不是也可以這么簡單?好象STL中也有一個(gè)for_each,試著改寫一下:
struct IfNotBusyThenDoSomeThing
{
IfNotBusyThenDoSomeThing(const Param& param)
: param_(param)
{}
void operator() (const MyClass& item)
{
if(!item.IsBusy())
item.DoSomeThing(param_);
}
private:
const Param& param_;
};
for_each(m_vecData.begin(), m_vecData.end(), IfNotBusyThenDoSomeThing(param));
不錯(cuò),for語句簡單了,但是卻多了
IfNotBusyThenDoSomeThing的定義,這代碼可是多了好幾倍。要是每個(gè)循環(huán)都要來這么一下,我還不如直接寫for,要來得爽快一些。或許還有別的辦法:
vector<MyClass> notBusyClass;
remove_copy_if(m_vecData.begin(), m_vecData.end(), inserter(notBusyClass, notBusyClass.begin()), mem_fun_ref(&MyClass::IsBusy));
for_each(notBusyClass.begin(), notBusyClass.end(), bind2nd(mem_fun_ref(&MyClass::DoSomeThing), param));
天哪,這種寫法好象更恐怖。而且,還不是每種情況都能用的:
1. notBusyClass不能是vector<const MyClass&>,因?yàn)椴荒芙⒅赶蛞玫闹羔槨_@就要求MyClass是可拷貝的。但就算是可拷貝的,有時(shí)候拷貝成本也是很高的。
2. MyClass::DoSomeThing的參數(shù)不能是引用(我們常定義參數(shù)為:const Param&),因?yàn)椴荒芏x引用的引用這種類型。
3. 一旦出現(xiàn)錯(cuò)誤,這錯(cuò)誤信息會(huì)讓人極其昏倒。
看來單靠標(biāo)準(zhǔn)C++是不成的。Boost的lambda的庫似乎很不錯(cuò),用用:
for_each(m_vecData.begin(), m_vecData.end(),
if_then( !bind(&MyClass::IsBusy, _1),
bind(&MyClass::DoSomeThing, _1, param)));
不錯(cuò),好了一些,但是還是很不好看。有沒有更好的?有,boost1.34新加入的BOOST_FOREACH:
BOOST_FOREACH(cosnt MyClass& item, m_vecData)
{
if(!item.IsBusy())
item.DoSomeThing(param);
}
Oh Yeah!
好了,問題來了,為什么C++不直接在語言中提供foreach這個(gè)功能呢?
個(gè)人認(rèn)為,原因有幾點(diǎn):
1. C/C++除了數(shù)組外,沒有內(nèi)置的容器,因此for語句足矣。
2. 當(dāng)C++進(jìn)化到STL的時(shí)候,C++標(biāo)準(zhǔn)委員會(huì)根本沒空去考慮其它的。
而其它高級語言之所以內(nèi)置了foreach,就是因?yàn)樗鼈円婚_始就提供了標(biāo)準(zhǔn)的容器庫和迭代/枚舉接口,因此提供foreach就順理成章了。
現(xiàn)在,總算C++開始考慮,由模板引入而造成的代碼復(fù)雜性的問題,這的確是Cpper的福音。因此,一系列相關(guān)的提案被提交。牽涉到上面代碼中的提案就有:
Decltype,
Lambda expressions and closures for C++,
proposal for new for-loop。
其中,最符合foreach要求的就是新的for循環(huán)。采用這個(gè)語句,上面的程序就可以這么寫:
for(const MyClass& item : m_vecData)
{
if(!item.IsBusy())
item.DoSomeThing(param);
}
不過,考慮到Decltype&auto提案已經(jīng)被采納,新的for-loop就不知道能不能再被采納。因?yàn)槭褂肈ecltype&auto后,程序可以這么寫:
for(auto iter = m_vecData.begin(), end = m_vecData.end(); iter != end; ++iter)
{
if(!iter->IsBusy())
iter->DoSomeThing(param);
}
似乎還是復(fù)雜點(diǎn)是吧?但是有了decltype&auto后,foreach功能可以用程序庫或宏的形式被模擬,BOOST_FOREACH就是這么做的。具體模擬的方式<<proposal for new for-loop>>提案寫的很清楚了。
同時(shí),假如lambda提案要是能再被通過的話,那就真的要開心了:
for_each(
m_vecData,
<>(item) extern(param)
{
if(!item.IsBusy())
item.DoSomeThing(param);
}
);
Cool!
不過,VC++2008倒是增加了foreach功能,不過關(guān)鍵字不是foreach,而是for each,這個(gè)讓人有點(diǎn)郁悶.要用的時(shí)候最好用宏定義替換一下,免得可移植性上出現(xiàn)問題.