eXile 的专栏

最简单的foreach实现(VC & GCC)

     foreach据说已经进了新的C++标准,不过在没有编译器支持以前,自己写一个也很容易。

(1)   foreach 标准用法: 

std::vector<int> vec;
foreach(int i,  vec) {
    std::cout  
<<  i;
}


     
    (2)VC实现

     在最新的VC版本中原来已经有了类似于foreach的支持,改个名字就行了:

#define foreach(var, container)   for each(var in containter)

   
    (3)GCC实现

    GCC没有内嵌支持,不过由于GCC支持typeof关键字, 所以实现起来也不是太难.  (有个bug, 在OwnWaterloo提醒下已经纠正)
template <typename C> struct foreach_helper {
    typename C::const_iterator it, end;
    foreach_helper (
const C& c) : it(c.begin()), end(c.end()) {}
};


#define RANDOM_VAR(name, line)     RANDOM_VAR_(name, line)
#define RANDOM_VAR_(name, line)    name ## line


#define foreach(var, container)  \
__typeof__(container) 
const&   RANDOM_VAR(_con_, __LINE__) = container; \
for (foreach_helper <__typeof__(container)> _fh_(RANDOM_VAR(_con_, __LINE__)); _fh_.it != _fh_.end; ++_fh_.it) \
for (var = *_fh_.it;; __extension__ ({break;}))

   
    这里有一个特殊的考虑,就是container有可能是一个临时对象,或者是某个函数的返回值。为了不对容器进行复制,利用了一个不太为人所知的C++特性,就是临时变量在存在引用时,生命期会由引用变量决定。这样保证在进行循环时始终有效。
   
   (4)性能

      我分别使用GCC和VC9进行了测试(优化选项都使用O2),结果表明使用foreach和普通的iterator 遍历几乎没有差别。不过gcc的遍历性能要明显好于VC9 (用个具有中国特色的结论,就是大约要好五倍),我的测试当然很粗略,不值得相信。

    本文由eXile 原创,转载请表明原贴地址。 http://www.cppblog.com/eXile/

posted on 2009-05-08 01:25 eXile 阅读(3865) 评论(10)  编辑 收藏 引用 所属分类: C/C++

评论

# re: 最简单的foreach实现(VC & GCC)[未登录] 2009-05-08 12:20 tom

用BOOST_FOREACH更好点,使用的是ISO标准C++。VC那是CLI扩展,非ISO标准.  回复  更多评论   

# re: 最简单的foreach实现(VC & GCC) 2009-05-08 12:42 OwnWaterloo

-------- -------- 引 -------- --------
这里有一个特殊的考虑,就是container有可能是一个临时对象,或者是某个函数的返回值。为了不对容器进行复制,利用了一个不太为人所知的C++特性,就是临时变量在存在引用时,生命期会由引用变量决定。这样保证在进行循环时始终有效。
-------- -------- 引 -------- --------


函数返回值就是临时对象的一种吧?
这个特性更准确描述应该是:
const 引用可以绑定到一个临时对象上,
临时对象的生命周期将延长至const引用超出作用域。
临时对象原本的生命周期仅到产生临时对象的完整表达式结束。


-------- -------- 分割线 -------- --------
是否可以考虑这样修改?
#define foreach(var, container) \
{ \
/... \
}

——1是可以避免临时对象的生命周期被延长到不需要的地方

——2是可以避免一个bug:
#define RANDOM_VAR(name, line) name ## line
这个宏不会以你想想中的样子工作。

至少要改成:
#define RANDOM_VAR(name, line) RANDOM_VAR_(name,line)
// 交给另一个宏
#define RANDOM_VAR_(name,line) name##line
// 才能启动rescan机制,将__LINE__展开


——3. 如果让foreach_helper有一个到container的const引用, 也就不需要单独的RANDOM_VAR去提升container的生命周期了。  回复  更多评论   

# re: 最简单的foreach实现(VC & GCC) 2009-05-08 12:46 OwnWaterloo

同时…… 非常不明白 ……
为什么很多C++程序员(甚至是许多老手)都喜欢使用下划线开头的标识符……
这是个非常不好的习惯……  回复  更多评论   

# re: 最简单的foreach实现(VC & GCC) 2009-05-08 13:53 eXile

@OwnWaterloo
谢谢提醒,RANDOM_VAR的定义确实不对,要改成你说的样子.
不过你说的加大括号或者foreach_helper加container引用的办法,是不行的。
至于,为什么使用下划线开头,正是因为这种命名方法不常用,所会才会避免偶然和其它变量重名的情况,一般也就是仅限于宏中使用。

  回复  更多评论   

# re: 最简单的foreach实现(VC & GCC) 2009-05-08 14:53 Wealth

用宏实现的话,其类型不安全。
在STL中已经有了for_each,肯定比自己实现的要高效。  回复  更多评论   

# re: 最简单的foreach实现(VC & GCC) 2009-05-08 16:54 空明流转

lambda 才是王道啊,嘎嘎。  回复  更多评论   

# re: 最简单的foreach实现(VC & GCC) 2009-05-08 17:07 空明流转

@Wealth
你从哪儿看出不安全?不高效?又从哪儿看出for_each和foreach是等价的了?  回复  更多评论   

# re: 最简单的foreach实现(VC & GCC) 2009-05-08 18:19 蚂蚁终结者

至于生命周期,大可不必用RANDOM_VAR这种方式,还是建议看一下BOOST_FOREACH
  回复  更多评论   

# re: 最简单的foreach实现(VC & GCC) 2009-05-08 21:31 eXile

@空明流转
确实,没有lambda之前,for_each没什么意思。不过好消息是VC2010将会支持lambda.  回复  更多评论   

# re: 最简单的foreach实现(VC & GCC) 2009-05-08 21:33 eXile

@蚂蚁终结者
BOOST_FOREACH 的那陀实现。。。还是算了吧  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理


导航

<2009年5月>
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

常用链接

留言簿(18)

随笔分类

随笔档案

服务器编程

搜索

最新评论

阅读排行榜

评论排行榜