从for到foreach

    一直在使用C/C++,对于循环语句while、do while、for,对于for情有独钟,因为其简洁、清晰、灵活。访问数组类型的变量,只有for写出来的语句是最易于阅读的,如:
int  arr[N]  =  { /* */ };
for ( int  i  =   0 ; i  <  N;  ++ i)
  printf(
" arr[%d] = %d/n " , i, arr[i]);

    然而,这种情况,到了STL时,就有些变味了:
for (vector < MyClass > ::const_iterator iter  =  m_vecData.begin(); iter  !=  m_vecData.end();  ++ iter)
{
    
if ( ! iter -> IsBusy())
        iter
-> DoSomeThing(param);
}
    这么长的一个for,不再给人一种清晰的感觉了。或许因为这个程序比较短,还没有太大的感觉,当回头去看自已的程序中,有不少这样的写法时,我就觉得一阵心烦。改改?
for (size_t i  =   0 ; i  <  m_vecData.size();  ++ i)
{
    
if ( ! m_vecData[i].IsBusy())
        m_vecData[i].DoSomeThing(param);
}
    不错,还是简单点好啊。但是因为这里举的是vector的例子。如果是list或是别的什么容器,就行不通了。
    其它的高级语言,都提供了foreach或是for in语句,写出来就很清晰:
foreach (item  in  m_vecData)
{
    
if ( ! item.IsBusy())
        item.DoSomeThing(param);
}
    C++是不是也可以这么简单?好象STL中也有一个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));
    不错,for语句简单了,但是却多了 IfNotBusyThenDoSomeThing的定义,这代码可是多了好几倍。要是每个循环都要来这么一下,我还不如直接写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&>,因为不能建立指向引用的指针。这就要求MyClass是可拷贝的。但就算是可拷贝的,有时候拷贝成本也是很高的。
    2. MyClass::DoSomeThing的参数不能是引用(我们常定义参数为:const Param&),因为不能定义引用的引用这种类型。
    3. 一旦出现错误,这错误信息会让人极其昏倒。

    看来单靠标准C++是不成的。Boost的lambda的库似乎很不错,用用:
    for_each(m_vecData.begin(), m_vecData.end(),
        if_then( !bind(
& MyClass::IsBusy, _1),
            bind(
& MyClass::DoSomeThing, _1, param)));
    不错,好了一些,但是还是很不好看。有没有更好的?有,boost1.34新加入的BOOST_FOREACH:
BOOST_FOREACH(cosnt MyClass &  item, m_vecData)
{
    
if ( ! item.IsBusy())
        item.DoSomeThing(param);
}
    Oh Yeah!

    好了,问题来了,为什么C++不直接在语言中提供foreach这个功能呢?
    个人认为,原因有几点:
    1. C/C++除了数组外,没有内置的容器,因此for语句足矣。
    2. 当C++进化到STL的时候,C++标准委员会根本没空去考虑其它的。
    而其它高级语言之所以内置了foreach,就是因为它们一开始就提供了标准的容器库和迭代/枚举接口,因此提供foreach就顺理成章了。

    现在,总算C++开始考虑,由模板引入而造成的代码复杂性的问题,这的确是Cpper的福音。因此,一系列相关的提案被提交。牵涉到上面代码中的提案就有: DecltypeLambda expressions and closures for C++proposal for new for-loop。  
    其中,最符合foreach要求的就是新的for循环。采用这个语句,上面的程序就可以这么写:
for ( const  MyClass &  item : m_vecData)
{
    
if ( ! item.IsBusy())
        item.DoSomeThing(param);
}

    不过,考虑到Decltype&auto提案已经被采纳,新的for-loop就不知道能不能再被采纳。因为使用Decltype&auto后,程序可以这么写:
for (auto iter  =  m_vecData.begin(), end  =  m_vecData.end(); iter  !=  end;  ++ iter)
{
    if ( ! iter->IsBusy())
        iter->DoSomeThing(param);
}
    似乎还是复杂点是吧?但是有了decltype&auto后,foreach功能可以用程序库或宏的形式被模拟,BOOST_FOREACH就是 这么做的。具体模拟的方式<<proposal for new for-loop>>提案写的很清楚了。
    同时,假如lambda提案要是能再被通过的话,那就真的要开心了:
for_each(
  m_vecData, 
  
<> (item) extern (param)
  {
    
if (!item.IsBusy())
        item.DoSomeThing(param);
  }
);
    Cool!

    不过,VC++2008倒是增加了foreach功能,不过关键字不是foreach,而是for each,这个让人有点郁闷.要用的时候最好用宏定义替换一下,免得可移植性上出现问题.

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值