{讨论}{技术}{C++}boost的理念和工程实用价值

445 views
Skip to first unread message

stlf

unread,
May 13, 2009, 8:21:35 AM5/13/09
to TopLanguage
boost 现在对于我们专业C++程序员应该是比较耳熟能详的了, 她对现代C++的影响不可谓不大, 在我的实际工程中也用到了一些boost库中
的内容(如 tuple, shared_ptr, bind, function,any等)。
在boost众多库之中有些确实给我们带来了方便, 然而有些确比较晦涩和略显罗嗦。于此同时boost库的引入又给我们的工程带来了一些复杂因素,其
中包括编译时间成本,和编译调试成本等,请不要忘记KISS原则。

在boost 中大量使用了模板这一"静态类生成器", 一个模板的参数化,在编译器看来好似是有一个类被声明了, boost中的模板在编译期间生成
了大量对于库用户不知道的类,即"中间类"(不知道这样描述是否合适?),而这些"中间类" 和静态设施一起在编译期使编译器帮我们 计算(很多是利用
模板的静态递归特性)了很多静态内容。其实这些都是复杂因素, 这些都对编译器提出了要求:静态计算也是要耗时的,耗的是编译时间, 长时间的编译对开
发者不是好的体验。

然而, 对一般应用而言用户要求得更多的可能是运行时的计算能力, 而boost库过多的使用模板---这一编译期的计算工具是否有点偏颇?

在一些著名的开源C++工程项目中我们也很少看到boost的身影, boost的实用价值到底有多大, 她的设计理念对C++语言而言是否是有益的?

jiang yudong

unread,
May 13, 2009, 8:33:24 AM5/13/09
to pon...@googlegroups.com
虽然从大一就开始接触C++了,但觉得自己始终是个门外汉,直到现在所使用的也仅仅是C++的一个很小的子集。不是自己对于C++诸多强大的语言特性不感兴趣,而是感觉实在没有用它们的必要……现在所写过的程序中,最大的核心代码量也只有2000行,不知那么多特性到底如何学习和使用。哎,先占个地方,等待牛人的回复。

2009/5/13 stlf <stlflin...@gmail.com>

qiaojie

unread,
May 13, 2009, 8:35:38 AM5/13/09
to pon...@googlegroups.com
只有2000行的话,还需要大量的训练,现在还不是思考语言特性该不该用的时候,等写到20w行的时候,再考虑这个问题。


2009/5/13 jiang yudong <nebul...@gmail.com>:

jiang yudong

unread,
May 13, 2009, 8:38:23 AM5/13/09
to pon...@googlegroups.com
你的意思是一个项目20w行?

2009/5/13 qiaojie <qia...@gmail.com>

qiaojie

unread,
May 13, 2009, 8:39:48 AM5/13/09
to pon...@googlegroups.com
当然是指总的代码量。当然,每个项目也应该具有一定的规模,写20w行hello world是没用的


2009/5/13 jiang yudong <nebul...@gmail.com>:

wang feng

unread,
May 13, 2009, 8:42:32 AM5/13/09
to pon...@googlegroups.com
stlf wrote:
> 在boost 中大量使用了模板这一"静态类生成器", 一个模板的参数化,在编译器看来好似是有一个类被声明了, boost中的模板在编译期间生成
> 了大量对于库用户不知道的类,即"中间类"(不知道这样描述是否合适?),而这些"中间类" 和静态设施一起在编译期使编译器帮我们 计算(很多是利用
> 模板的静态递归特性)了很多静态内容。其实这些都是复杂因素, 这些都对编译器提出了要求:静态计算也是要耗时的,耗的是编译时间, 长时间的编译对开
> 发者不是好的体验。
>
最近写的一段代码中用到了bessel函数,使用了
boost/math/special_functions.hpp 中的 cyl_bessel_j(double, double) 这个
函数,觉得boost很神奇,直接include头文件就成了,不用链接库;如果用gsl的
bessel函数,要链接libgsl 和 gslcblas;自己也写过一个,不过没有时间详细测
试,有点信心不足,就先用boost的了。

至于编译时间很长这个问题我也发现了,我的解决方法是把它包装一下,大致这样:
$ cat bessel.hh
#ifndef _BESSEL_H_INCLUDED
#define _BESSEL_H_INCLUDED

double bessel( double, double );

#endif

$ cat bessel.cc
#include <bessel.hh>

#include <boost/math/special_functions.hpp>

using namespace boost::math;

double bessel( double a, double x )
{
return cyl_bessel_j( a, x );
}


如果bessel.hh和bessel.cc没有改动,make的时候不会重新编译。

jiang yudong

unread,
May 13, 2009, 8:50:47 AM5/13/09
to pon...@googlegroups.com
恩,呵呵开个玩笑。我的总代码量仅有大约2w行左右(差了一个数量级),但是大多都以算法设计为主的小程序。发现自己现在现在编写规模大于2000行的程序就会因为种种设计上的问题而混乱不堪。感觉好的设计思路真是难求啊……关注中,继续练习……

2009/5/13 qiaojie <qia...@gmail.com>

qiaojie

unread,
May 13, 2009, 8:58:01 AM5/13/09
to pon...@googlegroups.com
我觉得boost是在把简单问题复杂化,像shared_ptr, bind, function, lambda,
foreach这些东西纯粹是语法糖,本来就是些很简单很基础的东西,应该用KISS的方法处理他们,可boost却用一个巨大的库去实现他们,这个理念我完全不认同。又因为boost本身是C++专家们开发的,由于其权威性所以更加具有误导性。

我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。


2009/5/13 stlf <stlflin...@gmail.com>:

Fei Yan

unread,
May 13, 2009, 8:58:25 AM5/13/09
to pon...@googlegroups.com
编译期所做的计算运用得当的话,可以很好的提高运行期的效率。

开源C++项目里边用boost少的缘故(我阅读过的是有几个的),可能和历史因素有关,而且很多都自己造了一些和boost某些基础设施类似的玩意。生命力长的开源项目不会在一开始的时候选择一个不成熟的东西来奠基,这些项目不少都比boost的年龄要大的多。

做科学计算,应该听说过blitz++这个东西,号称效率非常之高,也是将模板技术发挥的淋漓尽致,不过我没有去详细读过它的代码。

从Boost库的活跃程度上看,我不觉得它是孤芳自赏、没有人用的东西;最近1.39都出来了。某些前同事反映,不少做安全的公司都在大量应用boost某些基础构件,提高应用开发的生产力。


2009/5/13 stlf <stlflin...@gmail.com>

四不象

unread,
May 13, 2009, 9:23:14 AM5/13/09
to pon...@googlegroups.com
提到boost::function我就想到成员函数指针,这东西实在太丑陋了。
如果当初设计的时候提供一个类似C++ builder里的__closure关键字不就结了

missdeer

unread,
May 13, 2009, 11:32:50 AM5/13/09
to TopLanguage
这是C++的一个大问题,它爸就经常说的,要把一个特性定性为由语言来实现还是由库来实现,很重要也很头痛,那是一门哲学。。。残念。。。。

On May 13, 9:23 pm, 四不象 <tabris17...@gmail.com> wrote:
> 提到boost::function我就想到成员函数指针,这东西实在太丑陋了。
> 如果当初设计的时候提供一个类似C++ builder里的__closure关键字不就结了
>
> ----- Original Message -----
> From: "qiaojie" <qiao...@gmail.com>
> To: <pon...@googlegroups.com>
> Sent: Wednesday, May 13, 2009 8:58 PM
> Subject: [TL] Re: {讨论}{技术}{C++}boost的理念和工程实用价值
>
> > 我觉得boost是在把简单问题复杂化,像shared_ptr, bind, function, lambda,

> > foreach这些东西纯粹是语法糖,本来就是些很简单很基础的东西,应该用KISS的方法处理他们,可boost却用一个巨大的库去实现他们,这个理念我完全 不认同。又因为boost本身是C++专家们开发的,由于其权威性所以更加具有误导性。
>
> > 我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻 量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点 ,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。
>
> > 2009/5/13 stlf <stlflingfeit...@gmail.com>:

missdeer

unread,
May 13, 2009, 11:34:17 AM5/13/09
to TopLanguage
我觉得这话有点偏执,不然可以说那些啥Ruby、Python什么的都是C++的语法糖......

On May 13, 8:58 pm, qiaojie <qiao...@gmail.com> wrote:
> 我觉得boost是在把简单问题复杂化,像shared_ptr, bind, function, lambda,

> foreach这些东西纯粹是语法糖,本来就是些很简单很基础的东西,应该用KISS的方法处理他们,可boost却用一个巨大的库去实现他们,这个理念我完全 不认同。又因为boost本身是C++专家们开发的,由于其权威性所以更加具有误导性。
>
> 我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻 量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点 ,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。
>
> 2009/5/13 stlf <stlflingfeit...@gmail.com>:

qiaojie

unread,
May 13, 2009, 11:44:15 AM5/13/09
to pon...@googlegroups.com
首先,Ruby、Python跟C++是不等价的
其次,我不排斥语法糖,语法糖可以带来便利性,但这要看付出的代价,如果代价大于便利,那么就不能吃。糖大家都爱吃,但是吃多了发福就不好了。

2009/5/13 missdeer <miss...@gmail.com>:

Zhang Xiang

unread,
May 13, 2009, 9:07:54 AM5/13/09
to pon...@googlegroups.com
额~~我的项目到时大量用到boost的。

2009/5/13 Fei Yan <skyscr...@gmail.com>

DaNmarner

unread,
May 13, 2009, 11:30:56 AM5/13/09
to TopLanguage
Boost在下一到两个版本的C++标准里占了举足轻重的部分

up duan

unread,
May 13, 2009, 7:36:02 PM5/13/09
to pon...@googlegroups.com


2009/5/13 qiaojie <qia...@gmail.com>

我觉得boost是在把简单问题复杂化,像shared_ptr, bind, function, lambda,
foreach这些东西纯粹是语法糖,本来就是些很简单很基础的东西,应该用KISS的方法处理他们,可boost却用一个巨大的库去实现他们,这个理念我完全不认同。又因为boost本身是C++专家们开发的,由于其权威性所以更加具有误导性。

或许你说的boost复杂有道理,但是,你举得例子不当。基于现在的C++Spec,实现shared_ptr还能更简单么?bind能么?function能么?lambda能么?我不以为能。

还有你批评的ACE之类的库,它跟boost一样,都是为了追求工业级品质的。在代码中或许有许多你看上去完全没有必要的东西,但并不意味着别人会觉得完全没有必要,适应不同的平台和编译器并不简单。而C++的源代码如果想做到工业级必须能够适应不同的编译器。之所以Java、C#没有这样的问题,可以认为它们只有一个编译器【或者说所有的编译器都是完全一致的实现了语言规范的】。

其实主要问题在C++社区而不是这些库身上,库【以及任何软件产品】都可以看做社区的影子,似乎是The Art of UNIX Programming里面的一个观点吧。
 

我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。


我也很欣赏ATL,而且我认为它是诡异的递归模板参数使用方式的第一库,这也几乎构成了《现代C++设计》一书的主要技术支撑点。但是你说的编译不慢这个问题其实是误解。没有理由都是大量的使用模板一个库编译的慢而另一个编译的快。

lingfei t

unread,
May 13, 2009, 11:43:57 PM5/13/09
to pon...@googlegroups.com
boost是在试图使用户编程简单化, 她提供了一系列的portable工具给我们使用, 其中确实不
乏精巧实用的工具, 但有些库可能就有语法糖之嫌。我觉得她提供的工具确实很高级但有些是
不是一般用户最需要的 这一点是值得商榷的。

另外boost的众多库基本很难构成一个完整的架构体系,这也是其很难成为日常开发的基础类
库的原因。其实boost虽然有工业强度,但其本身承载的更多的还是实验性质。

说到底,c++程序员最需要的是一个系统化,简洁高效, 并且实用的的标准库。


2009/5/14 up duan <fix...@gmail.com>:

up duan

unread,
May 13, 2009, 11:52:17 PM5/13/09
to pon...@googlegroups.com


2009/5/14 lingfei t <stlflin...@gmail.com>

boost是在试图使用户编程简单化, 她提供了一系列的portable工具给我们使用, 其中确实不
乏精巧实用的工具, 但有些库可能就有语法糖之嫌。我觉得她提供的工具确实很高级但有些是
不是一般用户最需要的 这一点是值得商榷的。

嗯,不同人有不同的需要,boost提供什么是它的自由,可能没有提供我们需要的东西,但不能因此认为boost提供的不是一般用户最需要的。
 

另外boost的众多库基本很难构成一个完整的架构体系,这也是其很难成为日常开发的基础类
库的原因。其实boost虽然有工业强度,但其本身承载的更多的还是实验性质。

这也可以说是boost库的优势啊。boost不需要你修改程序风格,几乎是完全非侵入式的,不像MFC或者ACE,需要修改程序的结构以适应框架。
我倒不觉得除非提供完整的架构才能供日常开发使用。C的stdio也不是侵入式的,但是它难道不是日常开发的基础?跟别说那些随时使用的sin之类的。不需要是完整的开发框架才能被广泛使用吧。

boost确实有很多实现的色彩,但是那是boost库开发的过程,一旦进入到boost库里面,已经确保其有效和有用了,你可以看看一个库进入到boost中历经的阶段就知道了。
 

说到底,c++程序员最需要的是一个系统化,简洁高效, 并且实用的的标准库。

怀疑这一点永远不能实现。因为如果提供一个系统级的库,那么就意味着要抹平所有运行平台的差异,那还不如直接提供一个虚拟的运行平台【想没想到JVM??】呢,你觉得这是C++的方向么? 

qiaojie

unread,
May 14, 2009, 12:18:40 AM5/14/09
to pon...@googlegroups.com
> 2009/5/13 qiaojie <qia...@gmail.com>
>>
>> 我觉得boost是在把简单问题复杂化,像shared_ptr, bind, function, lambda,
>>
>> foreach这些东西纯粹是语法糖,本来就是些很简单很基础的东西,应该用KISS的方法处理他们,可boost却用一个巨大的库去实现他们,这个理念我完全不认同。又因为boost本身是C++专家们开发的,由于其权威性所以更加具有误导性。
>
> 或许你说的boost复杂有道理,但是,你举得例子不当。基于现在的C++Spec,实现shared_ptr还能更简单么?bind能么?function能么?lambda能么?我不以为能。
> 还有你批评的ACE之类的库,它跟boost一样,都是为了追求工业级品质的。在代码中或许有许多你看上去完全没有必要的东西,但并不意味着别人会觉得完全没有必要,适应不同的平台和编译器并不简单。而C++的源代码如果想做到工业级必须能够适应不同的编译器。之所以Java、C#没有这样的问题,可以认为它们只有一个编译器【或者说所有的编译器都是完全一致的实现了语言规范的】。
> 其实主要问题在C++社区而不是这些库身上,库【以及任何软件产品】都可以看做社区的影子,似乎是The Art of UNIX
> Programming里面的一个观点吧。
>
>>


既然shared_ptr,bind,function,lambda这些东西用C++实现起来很困难代价很大,那为什么一定要支持呢?我不认为这些语法糖可以提高软件生产效率。没有他们C++代码一样可以写,日子还是照样过,但是却减轻了程序员的很多脑力负担,不要忘记,程序的设计才是我们需要解决的主要矛盾,沉迷于这些杂七杂八的语法糖只会分散对主要问题的注意力,这程序还能设计的好么?想想Linus为什么要批判C++?C语言里的语法糖少的可怜,不是一样开发出了很多伟大的软件?
如果这些特性对程序设计的是重要的,那么应该由语言特性本身去支持,你不是也意识到是语言自身的限制造成的问题么?我们完全可以放弃C++,改用其他更高级的语言来完成。


>>
>> 我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。
>>
>
> 我也很欣赏ATL,而且我认为它是诡异的递归模板参数使用方式的第一库,这也几乎构成了《现代C++设计》一书的主要技术支撑点。但是你说的编译不慢这个问题其实是误解。没有理由都是大量的使用模板一个库编译的慢而另一个编译的快。


ATL编译不慢是因为代码量少,几千行的核心代码,放到预编译头文件里就完成编译了。而boost随便引入一个头文件就几千行了,又不可能都放到预编译头里去,编译速度自然就很慢了。

OxFAN

unread,
May 14, 2009, 12:04:20 AM5/14/09
to pon...@googlegroups.com
很多人都在说这个库哪里哪里不行,说那个库哪里哪里不行,但没见人给出一个“可行”的方案的。
更何况,这些被提出来的“缺点”,没有任何有力的证据证明他们真的是设计缺陷。

如果你使用一个库之前连自己的需求和这个库是否适合你的需求都不清楚,那么在此基础上的任何评价都是没有意义的。如果它适合,那么就用它,如果不适合,那就不要用,并且第二种情况很正常也很普遍,然后你只要去寻找更合适的就行了,而不应该在公共场合披露这个库所谓的“缺点”。

任何语言、库、系统都有它适用的地方,没有什么是完美的,不可能满足每个人的爱好,单纯的根据个人喜好来评判这个那个,说白了是浪费所有人的时间。

还有,看到前面有人又把别的语言扔出来了,就像c++之父说的那样,任何将其他语言与c++的比较都是没有意义的,因为基本没有公平的比较。

qiaojie

unread,
May 14, 2009, 1:21:16 AM5/14/09
to pon...@googlegroups.com
boost跟STL一样是个基础库,很多基础组件都是为了通用程序而写的,所以如果要用的话,肯定是适合几乎所有C++程序的,不存在你说的需求问题,所以不要偷换概念,大谈什么适用性的问题。boost花了那么大力气,动用了各种奇巧淫技去模拟那些高级语言的特性,典型的高射炮打蚊子,我不知道这能提高多少软件生产力,但是由此带来的问题是显而易见的,这不是个人喜好问题,而是一个事实。

2009/5/14 OxFAN <oday...@gmail.com>:

up duan

unread,
May 14, 2009, 2:26:47 AM5/14/09
to pon...@googlegroups.com


2009/5/14 qiaojie <qia...@gmail.com>

> 2009/5/13 qiaojie <qia...@gmail.com>
>>
>> 我觉得boost是在把简单问题复杂化,像shared_ptr, bind, function, lambda,
>>
>> foreach这些东西纯粹是语法糖,本来就是些很简单很基础的东西,应该用KISS的方法处理他们,可boost却用一个巨大的库去实现他们,这个理念我完全不认同。又因为boost本身是C++专家们开发的,由于其权威性所以更加具有误导性。
>
> 或许你说的boost复杂有道理,但是,你举得例子不当。基于现在的C++Spec,实现shared_ptr还能更简单么?bind能么?function能么?lambda能么?我不以为能。
> 还有你批评的ACE之类的库,它跟boost一样,都是为了追求工业级品质的。在代码中或许有许多你看上去完全没有必要的东西,但并不意味着别人会觉得完全没有必要,适应不同的平台和编译器并不简单。而C++的源代码如果想做到工业级必须能够适应不同的编译器。之所以Java、C#没有这样的问题,可以认为它们只有一个编译器【或者说所有的编译器都是完全一致的实现了语言规范的】。
> 其实主要问题在C++社区而不是这些库身上,库【以及任何软件产品】都可以看做社区的影子,似乎是The Art of UNIX
> Programming里面的一个观点吧。
>
>>


既然shared_ptr,bind,function,lambda这些东西用C++实现起来很困难代价很大,那为什么一定要支持呢?我不认为这些语法糖可以提高软件生产效率。没有他们C++代码一样可以写,日子还是照样过,但是却减轻了程序员的很多脑力负担,不要忘记,程序的设计才是我们需要解决的主要矛盾,沉迷于这些杂七杂八的语法糖只会分散对主要问题的注意力,这程序还能设计的好么?想想Linus为什么要批判C++?C语言里的语法糖少的可怜,不是一样开发出了很多伟大的软件?
如果这些特性对程序设计的是重要的,那么应该由语言特性本身去支持,你不是也意识到是语言自身的限制造成的问题么?我们完全可以放弃C++,改用其他更高级的语言来完成。


之所以一定要支持,是因为这些构造很有用。
你不觉得可以提高生产率,你决策C照样可以干所有的事,其实这个论调并不新鲜,因为以前很多人都说过汇编也可以干所有的事。
程序设计是主要矛盾,你的意思是次要矛盾就可以置之不理,就是鸡毛蒜皮的小事了?我们为什么不用磨制的石器搞四个现代化呢? 
C++不是正在往语言本身添加这些构造呢么?在没有之前,你可以坚持着裸体,有人却宁愿找些草叶子编织出来一件可用的衣服,这似乎是各自的自由吧。
没有看出来不用C++的理由,为什么就不能用C++来使用这些构造呢?

>>
>> 我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。
>>
>
> 我也很欣赏ATL,而且我认为它是诡异的递归模板参数使用方式的第一库,这也几乎构成了《现代C++设计》一书的主要技术支撑点。但是你说的编译不慢这个问题其实是误解。没有理由都是大量的使用模板一个库编译的慢而另一个编译的快。


ATL编译不慢是因为代码量少,几千行的核心代码,放到预编译头文件里就完成编译了。而boost随便引入一个头文件就几千行了,又不可能都放到预编译头里去,编译速度自然就很慢了。

ATL干的领域是单纯有限的。而Boost却是一个涉猎广泛的库,你的程序如果什么都不需要,自然没有编译速度的问题。对于少数需要的,放进预编译头也可以吧。
什么?你全都需要?那就忍受慢吧,毕竟,只是慢而已,比自己写的生产率高多了。

许海斌

unread,
May 14, 2009, 2:36:18 AM5/14/09
to TopLanguage
boost是一个及其庞大的库,里面有七八十个c++库,如果一棒子就把所有的库都打死,的确是非常的冤,不可否认确实有些库是动用了各种奇巧淫技去模
拟那些高级语言的特性,但是还是有大部分库在开发中还是非常有用的,打个比方吧,记得有段时间一直想写一个有可以建索引的数据结构,但是发现boost
中就有现成的multi_index,至于上面提及的shared_ptr, bind, function, lambda, 四个库还是有一定的用
途的

1、shared_ptr 不用说了,effective c++中很多地方说明其实用价值,举个最简单的例子,很多情况下,相信简单工厂返回一个
shared_ptr比一个new指针更好

2、bind 函数对象和函数指针相比,函数对象可以有状态的这个优势在bind中就体现的淋漓尽致,典型的for_each加上bind比一个循环加
上一堆函数调用肯定更加简洁优雅

3、lambda 和bind结合使用代码的可读性更加高,下面这段代码相信一眼就能看明白什么意思
std::find_if( first, last, bind( &X::name, _1 ) == "Peter" || bind
( &X::name, _1 ) == "Paul" );

4、function库 看看下面两段代码,相信前者的可读性更好
boost::function<int (X*, int)> f;
f = &X::foo;
X x;
f(&x, 5);

int (X::*f)(int);
f = &X::foo;
X x;
x.*f(5);


On 5月14日, 下午1时21分, qiaojie <qiao...@gmail.com> wrote:
> boost跟STL一样是个基础库,很多基础组件都是为了通用程序而写的,所以如果要用的话,肯定是适合几乎所有C++程序的,不存在你说的需求问题,所以不要-偷换概念,大谈什么适用性的问题。boost花了那么大力气,动用了各种奇巧淫技去模拟那些高级语言的特性,典型的高射炮打蚊子,我不知道这能提高多少软件生产-力,但是由此带来的问题是显而易见的,这不是个人喜好问题,而是一个事实。
>
> 2009/5/14 OxFAN <odayf...@gmail.com>:


>
>
>
> > 很多人都在说这个库哪里哪里不行,说那个库哪里哪里不行,但没见人给出一个"可行"的方案的。
> > 更何况,这些被提出来的"缺点",没有任何有力的证据证明他们真的是设计缺陷。

> > 如果你使用一个库之前连自己的需求和这个库是否适合你的需求都不清楚,那么在此基础上的任何评价都是没有意义的。如果它适合,那么就用它,如果不适合,那就不要-用,并且第二种情况很正常也很普遍,然后你只要去寻找更合适的就行了,而不应该在公共场合披露这个库所谓的"缺点"。


> > 任何语言、库、系统都有它适用的地方,没有什么是完美的,不可能满足每个人的爱好,单纯的根据个人喜好来评判这个那个,说白了是浪费所有人的时间。
>

> > 还有,看到前面有人又把别的语言扔出来了,就像c++之父说的那样,任何将其他语言与c++的比较都是没有意义的,因为基本没有公平的比较。- 隐藏被引用文字 -
>
> - 显示引用的文字 -

up duan

unread,
May 14, 2009, 2:50:51 AM5/14/09
to pon...@googlegroups.com


2009/5/14 qiaojie <qia...@gmail.com>

boost跟STL一样是个基础库,很多基础组件都是为了通用程序而写的,所以如果要用的话,肯定是适合几乎所有C++程序的,不存在你说的需求问题,所以不要偷换概念,大谈什么适用性的问题。boost花了那么大力气,动用了各种奇巧淫技去模拟那些高级语言的特性,典型的高射炮打蚊子,我不知道这能提高多少软件生产力,但是由此带来的问题是显而易见的,这不是个人喜好问题,而是一个事实。

下论断是容易的。
提高生产力不知道带来的问题显而易见。这是一个事实

你有证据支撑么?我不想听到你说我的意图论来避免给出证据。对我来说,唯一可见的问题不过是编译速度慢一些,但是至少比我自己实现好很多,而且也很好的提高了我的生产率,你说的事实是怎么一回事?莫非我的经历是一个虚幻?

我个人认为。boost不是高射炮打蚊子,因为其实对于职业软件开发人员来说,主要矛盾都是在分析设计阶段搞定的,次要矛盾是实现的大头,也是最大的工作量之所在。所以,解决次要矛盾的绝对不是打蚊子,而至少是打苍蝇:)。至于是不是高射炮,我倒确实不太关心,管他是不是呢,就算他是导弹,只要我可以免费的使用,我不在乎。当然,使用boost还是要付出一定代价的,但是我的权衡是:只要能用就用。在我看来,代价跟收益比还是很小的。

Ian Yang

unread,
May 14, 2009, 2:54:58 AM5/14/09
to pon...@googlegroups.com
觉得C++的库难流行有个很重要的原因是:用C++的开发者似乎对第三方库都很不信任,更情愿自己写一个。

Sincerely, Ian Yang

Sent from Shanghai, 31, China

up duan

unread,
May 14, 2009, 3:11:05 AM5/14/09
to pon...@googlegroups.com


2009/5/14 Ian Yang <doit...@gmail.com>

觉得C++的库难流行有个很重要的原因是:用C++的开发者似乎对第三方库都很不信任,更情愿自己写一个。

Sincerely, Ian Yang

Sent from Shanghai, 31, China

照我的看法,这只是一个结果,而不是一个原因。

为什么Javaer对Java库能够信任C#er对.NET库能够信任,而C++er对C++库不能信任?因为他们可挑选的太多了,他们能看透实现的太多了,所以他们会觉得自己也可以而且完全应该自己实现一个。

当然,他们之所以能看透,能挑选,也是因为大多数C++库大多数都是一个小小的抽象也实现,都没有到达Java库和.net库那种庞大和平台级别。这种现象的一个原因我前面说过:C++不是一个平台,只是一个语言。另一个原因就是历史,那时候人们总是提供细粒度的组件以供重用,跟现在的趋势不同,现在是倾向于提供越来越大的组件。这个趋势跟人们对计算机的期望值越来越高有密切的关系,现在的计算机承载着人类生产力【本来想说人类文明的,觉得太大了点:)】的很大的一部分,要执行越来越庞大越来越复杂的任务,所以,基础组件个头大一点才好掌控,才好控制复杂度。

基于这些理由,C++程序员倾向于自己实现库,就算自己不实现,也倾向于看透别人库的实现。比如:qiaojie就用看透C++库如此费神儿批判C++,我觉得他可能从来没有试图去看透过.net库的实现:)。

qiaojie

unread,
May 14, 2009, 3:19:30 AM5/14/09
to pon...@googlegroups.com
那些高谈阔论的论调我就不再多说了,纯属嚼舌根。
还是喜欢这种具体的实例,就事论事,有的放矢。

2009/5/14 许海斌 <this...@gmail.com>:


> boost是一个及其庞大的库,里面有七八十个c++库,如果一棒子就把所有的库都打死,的确是非常的冤,不可否认确实有些库是动用了各种奇巧淫技去模
> 拟那些高级语言的特性,但是还是有大部分库在开发中还是非常有用的,打个比方吧,记得有段时间一直想写一个有可以建索引的数据结构,但是发现boost
> 中就有现成的multi_index,至于上面提及的shared_ptr, bind, function, lambda, 四个库还是有一定的用
> 途的
>
> 1、shared_ptr 不用说了,effective c++中很多地方说明其实用价值,举个最简单的例子,很多情况下,相信简单工厂返回一个
> shared_ptr比一个new指针更好

smart pointer我也喜欢,我以前用的最多的是CComPtr,那时候我的对象是COM风格的。现在会用些更轻量的引用计数对象,自己实现一个smart
pointer只要区区百行代码,引用一个庞大的boost库有点可怕。


> 2、bind 函数对象和函数指针相比,函数对象可以有状态的这个优势在bind中就体现的淋漓尽致,典型的for_each加上bind比一个循环加
> 上一堆函数调用肯定更加简洁优雅

for_each我从来不用,C++没有lambda,写出来的for_each代码是很丑陋的,宁可用for的。函数对象最大的问题是不能定义在函数里面,导致本来一段高内聚的代码变得东一块西一块,函数对象里虽然可以带状态,但是这些状态要共享起来又非常麻烦。用惯脚本语言的lambda以后,再看C++函数对象,会有种想吐的感觉。


>
> 3、lambda 和bind结合使用代码的可读性更加高,下面这段代码相信一眼就能看明白什么意思
> std::find_if( first, last, bind( &X::name, _1 ) == "Peter" || bind
> ( &X::name, _1 ) == "Paul" );

X是什么?_1是什么?bind( &X::name, _1 )又是什么?我完全看不明白这是什么意思。bind( &X::name, _1 )
== "Peter" || bind( &X::name, _1 ) == "Paul"

>
> 4、function库 看看下面两段代码,相信前者的可读性更好
> boost::function<int (X*, int)> f;
> f = &X::foo;
> X x;
> f(&x, 5);
>
> int (X::*f)(int);
> f = &X::foo;
> X x;
> x.*f(5);

用C++的人绝对不写 x.*f(5); 这种变态代码的,我以前也用Loki::Functor,跟function是一回事,
不过后来发现意义不大,大多数底层代码用不上这玩意,高层的逻辑代码大部分用脚本或者
C#去写了,更用不上了。这玩意的使用也不是免费的,对象的生命周期不太好管理,会带来
额外的复杂性。

qiaojie

unread,
May 14, 2009, 3:26:40 AM5/14/09
to pon...@googlegroups.com
2009/5/14 up duan <fix...@gmail.com>:


我没有全面批判C++,事实上我仍然会有一半的工作基于C++来开发,我只是针对某些库滥用C++的情况做一些批判,
C++很灵活用法很多,用好用坏千差万别,这个在其他语言里是非常少见的,所以有争议也是非常正常的。

另外,对 .net的底层实现机制我也很有兴趣啊,用C++/CLI的话会比较注重这方面。

许海斌

unread,
May 14, 2009, 4:47:07 AM5/14/09
to TopLanguage
boost是一个及其庞大的库,里面有七八十个c++库,如果一棒子就把所有的库都打死,的确是非常的冤,不可否认确实有些库是动用了各种奇巧
淫技去模
拟那些高级语言的特性,但是还是有大部分库在开发中还是非常有用的,打个比方吧,记得有段时间一直想写一个有可以建索引的数据结构,但是发现

boost
中就有现成的multi_index,至于上面提及的shared_ptr, bind, function, lambda, 四个库还是有一定的

途的

> 1、shared_ptr 不用说了,effective c++中很多地方说明其实用价值,举个最简单的例子,很多情况下,相信简单工厂返回一个
> shared_ptr比一个new指针更好

smart pointer我也喜欢,我以前用的最多的是CComPtr,那时候我的对象是COM风格的。现在会用些更轻量的引用计数对象,自己实现一
个smart
pointer只要区区百行代码,引用一个庞大的boost库有点可怕。

看到什么东西都喜欢自己实现不是一个好习惯,我就见过c++自己写链表而不用std::list的,(我这人说话比较直,还希望qiaojie兄台多多
包涵,下同),
本人从事证券行业,除了业务相关的代码都要自己写之外,其他的东西都喜欢找现成的,有时候人懒点反而更好


> 2、bind 函数对象和函数指针相比,函数对象可以有状态的这个优势在bind中就体现的淋漓尽致,典型的for_each加上bind比一个循环加
> 上一堆函数调用肯定更加简洁优雅

for_each我从来不用,C++没有lambda,写出来的for_each代码是很丑陋的,宁可用for的。函数对象最大的问题是不能定义在函数

里面,导-致本来一段高内聚的代码变得东一块西一块,函数对象里虽然可以带状态,但是这些状态要共享起来又非常麻烦。用惯脚本语言的lambda以后,
再看C++函数对象-,会有种想吐的感觉。

这里谈到函数对象了,函数对象相比函数指针有很多优势,这个就不再多说了,我倒不认为for_each的代码是很丑陋的,呵呵,这个估计就似乎审美观的
问题了吧,
当然,要和脚本语言的代码比优雅,c++肯定是不行的啦,还有一个额外的好处就是,for_each加上lambda相比手写循环能带来性能上的少许提


> 3、lambda 和bind结合使用代码的可读性更加高,下面这段代码相信一眼就能看明白什么意思
> std::find_if( first, last, bind( &X::name, _1 ) == "Peter" || bind
> ( &X::name, _1 ) == "Paul" );

X是什么?_1是什么?bind( &X::name, _1 )又是什么?我完全看不明白这是什么意思。bind( &X::name,
_1 )
== "Peter" || bind( &X::name, _1 ) == "Paul"

如果我的项目组来了一个有一定c++基础的新人,我会告诉他,你花半个小时看看boost::bind和boost::lambda的帮助,以后就永远
也不用写一大堆循环啦,
相信他会很高兴的


> 4、function库 看看下面两段代码,相信前者的可读性更好
> boost::function<int (X*, int)> f;
> f = &X::foo;
> X x;
> f(&x, 5);

> int (X::*f)(int);
> f = &X::foo;
> X x;
> x.*f(5);

用C++的人绝对不写 x.*f(5); 这种变态代码的,我以前也用Loki::Functor,跟function是一回事,
不过后来发现意义不大,大多数底层代码用不上这玩意,高层的逻辑代码大部分用脚本或者
C#去写了,更用不上了。这玩意的使用也不是免费的,对象的生命周期不太好管理,会带来
额外的复杂性。

boost::function我在实际工作中确实用的不多,但是我在想哪天要用到成员函数指针的时候,
除了上面第一种写法之外,怎么写才能更加直观

On 5月14日, 下午3时19分, qiaojie <qiao...@gmail.com> wrote:
> 那些高谈阔论的论调我就不再多说了,纯属嚼舌根。
> 还是喜欢这种具体的实例,就事论事,有的放矢。
>

> 2009/5/14 许海斌 <thisis...@gmail.com>:


>
> > boost是一个及其庞大的库,里面有七八十个c++库,如果一棒子就把所有的库都打死,的确是非常的冤,不可否认确实有些库是动用了各种奇巧淫技去模
> > 拟那些高级语言的特性,但是还是有大部分库在开发中还是非常有用的,打个比方吧,记得有段时间一直想写一个有可以建索引的数据结构,但是发现boost
> > 中就有现成的multi_index,至于上面提及的shared_ptr, bind, function, lambda, 四个库还是有一定的用
> > 途的
>
> > 1、shared_ptr 不用说了,effective c++中很多地方说明其实用价值,举个最简单的例子,很多情况下,相信简单工厂返回一个
> > shared_ptr比一个new指针更好
>
> smart pointer我也喜欢,我以前用的最多的是CComPtr,那时候我的对象是COM风格的。现在会用些更轻量的引用计数对象,自己实现一个smart
> pointer只要区区百行代码,引用一个庞大的boost库有点可怕。
>
> > 2、bind 函数对象和函数指针相比,函数对象可以有状态的这个优势在bind中就体现的淋漓尽致,典型的for_each加上bind比一个循环加
> > 上一堆函数调用肯定更加简洁优雅
>

> for_each我从来不用,C++没有lambda,写出来的for_each代码是很丑陋的,宁可用for的。函数对象最大的问题是不能定义在函数里面,导-致本来一段高内聚的代码变得东一块西一块,函数对象里虽然可以带状态,但是这些状态要共享起来又非常麻烦。用惯脚本语言的lambda以后,再看C++函数对象-,会有种想吐的感觉。

LeeoNix

unread,
May 14, 2009, 4:54:10 AM5/14/09
to pon...@googlegroups.com

for_each我从来不用,C++没有lambda,写出来的for_each代码是很丑陋的,宁可用for的。函数对象最大的问题是不能定义在函数里面,导致本来一段高内聚的代码变得东一块西一块,函数对象里虽然可以带状态,但是这些状态要共享起来又非常麻烦。用惯脚本语言的lambda以后,再看C++函数对象,会有种想吐的感觉。


仅仅是你从来不用而已,我贴一段Stroustrup的代码,我看到的是优雅的设计,而不是你说的麻烦:

Bjarne: 如果你面对的问题既需要某些运行期决议(需要面向对象编程),又具有一些能够从编译期决议中获益的方面(泛型编程的用武之地)的话,那么你就需要将面向对象编程和泛型编程结合起来。例如,面向对象编程的经典例子 — 将一个保存了shape的容器中的所有元素都显示出来就属于这类问题。几十年前我第一次在Simula中看到过这个例子,后来直到遇到了泛型编程,我才看到它的改进实现。考虑以下代码:

void draw_all(vector<Shape*>& vs)
{
    for (int i=0; i<vs.size(); ++i) vs[i]->draw();

我猜想这并不能被看作纯粹的面向对象编程,因为我直接利用了“vs是一个装有Shape*元素的vector”这个事实。毕竟,类型的参数化通常是被认为属于泛型编程的范畴。我们也可以消除这种对静态类型信息的使用(所谓“不纯粹的面向对象编程”): 

void draw_all(Object* container)
{
    Vector* v = dynamic_cast<Vector*>(container);
    for (int i=0; i<v.size(); ++i)
    {
        Shape* ps = dynamic_cast<Shape*>(v[i]);
        ps->draw();
    }

但凡鼓励以上这种风格的语言,其语法通常都比较漂亮,然而这个例子却说明了当你把静态类型信息的使用减至最小的时候发生了什么。如今,在C++或其它语言中,仍然有人在使用这种风格。我只是希望他们在错误处理方面有系统化的准备。 

在前一个例子中,vector<Shap*>依赖于对泛型编程的一个最简单的运用:vector的元素类型被参数化了,而且我们的示例代码正获益于此。在这个方向上我们还可以走得更远,即推而广之到所有标准库容器身上: 

template<class Container> void draw_all(Container& cs)
{
    for (typename C::iterator p=cs.begin(); p!=cs.end(); ++p)
        (*p)->draw();

例如,这段代码就既可以作用于vector上,又可以作用于list上。编译期决议确保我们不用为这种泛化处理付出任何运行期额外代价。我们还可以通过在draw_all()的使用接口中运用迭代器,从而进行进一步的泛化处理: 

template<class Iter> void draw_all(Iter fist, Iter last)
{
    for (; first!=last; ++first)
        (*first)->draw();

这就使内建数组类型都得到了支持: 

Shape* a[max];
//
a中填充Shape*类型的元素
draw_all(a,a+max); 

我们还可以结合运用标准库算法for_each()和函数适配器mem_fun()来消除显式的循环: 

template<class Iter> void draw_all(Iter fist, Iter last)
{
    for_each(first, last, mem_fun(&Shape::draw);

在这些例子中,我们结合了面向对象(对虚函数draw()的调用以及对类继承体系的假设)和泛型编程(参数化的容器和算法)技术。我看不出如果这两种编程风格(即所谓的“范型”)各自独立运用如何达到同样好的效果。这也是一个简单的“多范型编程”的例子。 

我认为在设计和编程技术方面,我们还需要做更多的工作,以便确定出“关于何时采用哪种范型以及如何结合运用它们”的更为具体的规则。为此,我们还需要一个比“多范型编程”更好的名字。 

注意,这也是一个关于编译错误信息变得可怕的例子,因为我们并没有显式地表达出我们的假设。例如,我们假设容器里的元素类型为Shape*,然而在代码中,这个假设却相当隐晦。这种情况下我们可以使用约束类(此处为Point_to): 

template<class Iter> void draw_all(Iter fist, Iter last)
{
    Points_to<Iter,Shape*>();
    for_each(first, last, mem_fun(&Shape::draw);

然而我们又确实很想说明“firstlast必须为前向迭代器”: 

template<Forward_iterator<Shape*> Iter>
void draw_all(Iter fist, Iter last)
{
    for_each(first, last, mem_fun(&Shape::draw);

这是“concepts”可以大展拳脚的地方之一。


许海斌

unread,
May 14, 2009, 4:58:40 AM5/14/09
to TopLanguage

刚才发的比较乱,整理了一下

On 5月14日, 下午3时19分, qiaojie <qiao...@gmail.com> wrote:

> 那些高谈阔论的论调我就不再多说了,纯属嚼舌根。
> 还是喜欢这种具体的实例,就事论事,有的放矢。
>

> 2009/5/14 许海斌 <thisis...@gmail.com>:


>
> > boost是一个及其庞大的库,里面有七八十个c++库,如果一棒子就把所有的库都打死,的确是非常的冤,不可否认确实有些库是动用了各种奇巧淫技去模
> > 拟那些高级语言的特性,但是还是有大部分库在开发中还是非常有用的,打个比方吧,记得有段时间一直想写一个有可以建索引的数据结构,但是发现boost
> > 中就有现成的multi_index,至于上面提及的shared_ptr, bind, function, lambda, 四个库还是有一定的用
> > 途的
>
> > 1、shared_ptr 不用说了,effective c++中很多地方说明其实用价值,举个最简单的例子,很多情况下,相信简单工厂返回一个
> > shared_ptr比一个new指针更好
>
> smart pointer我也喜欢,我以前用的最多的是CComPtr,那时候我的对象是COM风格的。现在会用些更轻量的引用计数对象,自己实现一个smart
> pointer只要区区百行代码,引用一个庞大的boost库有点可怕。

看到什么东西都喜欢自己实现不是一个好习惯,我就见过c++自己写链表而不用std::list的,(我这人说话比较直,还希望qiaojie兄台多
多 包涵,下同), 本人从事证券行业,除了业务相关的代码都要自己写之外,其他的东西都喜欢找现成的,有时候人懒点反而更好

>
> > 2、bind 函数对象和函数指针相比,函数对象可以有状态的这个优势在bind中就体现的淋漓尽致,典型的for_each加上bind比一个循环加
> > 上一堆函数调用肯定更加简洁优雅
>

> for_each我从来不用,C++没有lambda,写出来的for_each代码是很丑陋的,宁可用for的。函数对象最大的问题是不能定义在函数里面,导-致本来一段高内聚的代码变得东一块西一块,函数对象里虽然可以带状态,但是这些状态要共享起来又非常麻烦。用惯脚本语言的lambda以后,再看C++函数对象-,会有种想吐的感觉。
>
>

这里谈到函数对象了,函数对象相比函数指针有很多优势,这个就不再多说了,我倒不认为for_each的代码是很丑陋的,呵呵,这个估计就似乎审美观的
问题了吧,当然,要和脚本语言的代码比优雅,c++肯定是不行的啦,还有一个额外的好处就是,for_each加上lambda相比手写循环能带来性能
上的少许提升


>


> > 3、lambda 和bind结合使用代码的可读性更加高,下面这段代码相信一眼就能看明白什么意思
> > std::find_if( first, last, bind( &X::name, _1 ) == "Peter" || bind
> > ( &X::name, _1 ) == "Paul" );
>
> X是什么?_1是什么?bind( &X::name, _1 )又是什么?我完全看不明白这是什么意思。bind( &X::name, _1 )
> == "Peter" || bind( &X::name, _1 ) == "Paul"
>

如果我的项目组来了一个有一定c++基础的新人,我会告诉他,你花半个小时看看boost::bind和boost::lambda的帮助,以后就永远
也不用写一大堆循环啦, 相信他会很高兴的

>
>


> > 4、function库 看看下面两段代码,相信前者的可读性更好
> > boost::function<int (X*, int)> f;
> > f = &X::foo;
> > X x;
> > f(&x, 5);
>
> > int (X::*f)(int);
> > f = &X::foo;
> > X x;
> > x.*f(5);
>
> 用C++的人绝对不写 x.*f(5); 这种变态代码的,我以前也用Loki::Functor,跟function是一回事,
> 不过后来发现意义不大,大多数底层代码用不上这玩意,高层的逻辑代码大部分用脚本或者
> C#去写了,更用不上了。这玩意的使用也不是免费的,对象的生命周期不太好管理,会带来
> 额外的复杂性。

boost::function我在实际工作中确实用的不多,但是我在想哪天要用到成员函数指针的时候, 除了上面第一种写法之外,怎么写才能更加直

qiaojie

unread,
May 14, 2009, 4:59:03 AM5/14/09
to pon...@googlegroups.com
2009/5/14 许海斌 <this...@gmail.com>:

> boost是一个及其庞大的库,里面有七八十个c++库,如果一棒子就把所有的库都打死,的确是非常的冤,不可否认确实有些库是动用了各种奇巧
> 淫技去模
> 拟那些高级语言的特性,但是还是有大部分库在开发中还是非常有用的,打个比方吧,记得有段时间一直想写一个有可以建索引的数据结构,但是发现
> boost
> 中就有现成的multi_index,至于上面提及的shared_ptr, bind, function, lambda, 四个库还是有一定的
> 用
> 途的
>
>> 1、shared_ptr 不用说了,effective c++中很多地方说明其实用价值,举个最简单的例子,很多情况下,相信简单工厂返回一个
>> shared_ptr比一个new指针更好
>
> smart pointer我也喜欢,我以前用的最多的是CComPtr,那时候我的对象是COM风格的。现在会用些更轻量的引用计数对象,自己实现一
> 个smart
> pointer只要区区百行代码,引用一个庞大的boost库有点可怕。
>
> 看到什么东西都喜欢自己实现不是一个好习惯,我就见过c++自己写链表而不用std::list的,(我这人说话比较直,还希望qiaojie兄台多多
> 包涵,下同),
> 本人从事证券行业,除了业务相关的代码都要自己写之外,其他的东西都喜欢找现成的,有时候人懒点反而更好
>

拿来主义也是我一贯奉行的标准,当然这事得看具体情况,为了一个smart pointer而引入boost库我觉得代价太大了点,
其实Loki::SmartPointer我也用过,不过不符合我的使用习惯和设计理念:-) 所以就干掉,自己实现了一个。不过,不要
就此认为我的习惯就是凡事都喜欢自己实现。

qiaojie

unread,
May 14, 2009, 5:02:42 AM5/14/09
to pon...@googlegroups.com
你这例子太过简单

如果代码是这样的:
void draw_all(vector<Shape*>& vs, Graphics* graph)


{
for (int i=0; i<vs.size(); ++i)

if(vs[i]->IsVisible())
vs[i]->draw(graph);
}
又该怎么办呢?

2009/5/14 LeeoNix <leeo...@gmail.com>:


>>
>>
>> for_each我从来不用,C++没有lambda,写出来的for_each代码是很丑陋的,宁可用for的。函数对象最大的问题是不能定义在函数里面,导致本来一段高内聚的代码变得东一块西一块,函数对象里虽然可以带状态,但是这些状态要共享起来又非常麻烦。用惯脚本语言的lambda以后,再看C++函数对象,会有种想吐的感觉。
>>
>
> 仅仅是你从来不用而已,我贴一段Stroustrup的代码,我看到的是优雅的设计,而不是你说的麻烦:
>
> Bjarne:
> 如果你面对的问题既需要某些运行期决议(需要面向对象编程),又具有一些能够从编译期决议中获益的方面(泛型编程的用武之地)的话,那么你就需要将面向对象编程和泛型编程结合起来。例如,面向对象编程的经典例子

> --

LeeoNix

unread,
May 14, 2009, 5:14:20 AM5/14/09
to pon...@googlegroups.com
不是我的例子,是Bjarne Stroustrup的例子。

世界上没有你说的万金油,提出某个特例就把for_each全部都给否定了。

你从来不用,并不代表别人不用,你看着丑陋,不代表别人写的丑陋。

而Bjarne Stroustrup很好的给你证明了这个。

如果带一个参数可以用mem_fun1来把函数做出来,用for_each实现。

当然你可以提更多极端要求。但是仍旧证明不了for_each被很好的推广,包括Bjarne Stroustrup本人。

2009/5/14 qiaojie <qia...@gmail.com>

up duan

unread,
May 14, 2009, 5:18:46 AM5/14/09
to pon...@googlegroups.com
直接把我在另一个线索里发的帖子copy过来:)

for_each其实相当于把for() {这儿}花括号里面的东西提炼出来了,有些人习惯,有些人不习惯,不过总体而言,写在for花括号里面的东西相对自由和灵活,而for_each却能强迫你考虑清楚结构和接口。只能说各有利弊吧。
lambda引入到C++以后,我预计for_each会比以前受欢迎。
对于for_each引入一个额外的name,这依赖于是否有利于可理解性,是否有利于重用,但是显然破坏了局部性。
在没有lambda之前,可以用一个unnamed namespace来制造一个“local name”。

2009/5/14 LeeoNix <leeo...@gmail.com>

qiaojie

unread,
May 14, 2009, 5:19:05 AM5/14/09
to pon...@googlegroups.com
我只想知道这个例子你用for_each怎么写?
难道这个例子很过分,很特殊吗?


2009/5/14 LeeoNix <leeo...@gmail.com>:

up duan

unread,
May 14, 2009, 5:31:49 AM5/14/09
to pon...@googlegroups.com


2009/5/14 qiaojie <qia...@gmail.com>
我只想知道这个例子你用for_each怎么写?
难道这个例子很过分,很特殊吗?
我不知道用for_each写有什么问题。 
一点都不特殊,显然,for的{}可以直接使用context,而for_each需要参数传递进去,你觉得不能传递进去么?bind就可以把参数传进去了呀。
以后,如果C++的lambda引入[graph](it){这儿可以直接使用graph},就不在需要这么多辅助设施搞定了。

LeeoNix

unread,
May 14, 2009, 5:32:29 AM5/14/09
to pon...@googlegroups.com
为什么要说这个?我只是举个例子说明而已。

就是写了又如何?证明了什么?又证明了你说的for_each不好用,不适合,语法很丑陋?

你不就是想让我说出这句话吗?

就算for_each解决了30%的问题,那也有存在的必要。就算for_each不适合80%的循环设计,哪又如何呢?

你用这个例子去抹杀for_each的价值?

2009/5/14 qiaojie <qia...@gmail.com>

qiaojie

unread,
May 14, 2009, 5:37:43 AM5/14/09
to pon...@googlegroups.com
你觉得没问题就写出来看看嘛, 不然我们怎么评价用for_each到底好不好呢?
不要跟我说什么C++引入lambda会怎么怎么样?那都是八字没一撇的事情。


2009/5/14 up duan <fix...@gmail.com>:

qiaojie

unread,
May 14, 2009, 5:42:38 AM5/14/09
to pon...@googlegroups.com
我的意思是你的例子太简单,没有代表性,所以举个更一般化的例子,我的例子也没有什么变态的地方吧?
如果for_each不适合这个例子,那么至少我们也知道了for_each的适用范围,也没什么害处吧?

2009/5/14 LeeoNix <leeo...@gmail.com>:

LeeoNix

unread,
May 14, 2009, 5:42:56 AM5/14/09
to pon...@googlegroups.com
你的理念里面有个误区,就是for_each是可以完全替代for循环的。

请看清楚for each,每个都要用的含义。

而你的需求不是一个for_each,而是具有if判断的for循环,

按照stl分类命名,其实是一个for_each_if,可以使用boost库的定义:

http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?STLAlgorithmExtensions/ForEachIf

2009/5/14 qiaojie <qia...@gmail.com>

LeeoNix

unread,
May 14, 2009, 5:50:44 AM5/14/09
to pon...@googlegroups.com
使用for_each_if可以这么写:

template<Forward_iterator<Shape*> Iter>
void draw_all(Iter fist, Iter last, Graphics* graph)
{
    for_each_if(first, last, mem_fun(&Shape::IsVisible), bind2nd(mem_fun1(&
Shape::draw), graph));
}


应该是这样了。

2009/5/14 qiaojie <qia...@gmail.com>

qiaojie

unread,
May 14, 2009, 5:53:15 AM5/14/09
to pon...@googlegroups.com
哦,好吧,原来是
for_each_if(first, last, mem_fun(&Shape::IsVisible),
mem_fun1(&Shape::draw, graph));
是这样写吧?我是第一次知道。


那如果,例子再改一下:


void draw_all(vector<Shape*>& vs, Graphics* graph)
{
for (int i=0; i<vs.size(); ++i)
if(vs[i]->IsVisible())
vs[i]->draw(graph);

else
vs[i]->draw_hide(graph);
}

那是不是boost里还有一个for_each_if_else啊?
是不是还要发明一个for_each_switch 啊?


2009/5/14 LeeoNix <leeo...@gmail.com>:

LeeoNix

unread,
May 14, 2009, 5:55:54 AM5/14/09
to pon...@googlegroups.com
你这叫抬杠,stl里面就一个find_if,一个remove_if,这个是stl提供的方式。

只是解决大多数的问题而提供的算法,就可以了。

如果你有复杂逻辑,自己去写for循环就可以了,不是叫你主动去套某个函数,

这样思考是不是很傻?

就是脚本语言里的foreach也不是万金油。

2009/5/14 qiaojie <qia...@gmail.com>

LeeoNix

unread,
May 14, 2009, 5:57:19 AM5/14/09
to pon...@googlegroups.com
如果你需求这么大,干嘛不叫C++标准委员会生成一个find_if_else给你用?

我们讨论是好的,但不是拿特例去抬杠,然后证明你的结论是对的。

只要for_each解决了20%的问题,就是一个很有用的函数。

2009/5/14 qiaojie <qia...@gmail.com>

许海斌

unread,
May 14, 2009, 5:59:05 AM5/14/09
to TopLanguage

这种情况大致可以考虑放弃for_each了,我觉得for_each在很多情况下可以让我们的程序更加简洁但不是全部,如果非要写的话
for_each + bind + lambda大致如下吧

for_each(vs.begin(), vs.end(), if_then(bind(&shape::visible, _1) ==
true, bind(&shape::draw, _1)(graph));

On 5月14日, 下午5时31分, up duan <fixo...@gmail.com> wrote:
> 2009/5/14 qiaojie <qiao...@gmail.com>

Ian Yang

unread,
May 14, 2009, 5:59:41 AM5/14/09
to pon...@googlegroups.com
写个functor draw_if_visible

或者用lambda

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

using namespace boost::lambda;

std::for_each(
vs.begin(), vs.end(),
if_(bind(&Shape::IsVisible, _1))
[
bind(&Shape::draw, _1, graph)
]
);

或者BOOST_FOREACH

BOOST_FOREACH(Sharp* s, vs)
{
if (s->isVisible())
s->draw(graph);
}

Sincerely, Ian Yang

Sent from Shanghai, 31, China


2009/5/14 qiaojie <qia...@gmail.com>:

Ian Yang

unread,
May 14, 2009, 6:04:19 AM5/14/09
to pon...@googlegroups.com
switch也有

std::for_each(v.begin(), v.end(),
(
switch_statement(
_1,
case_statement<0>(std::cout << constant("zero")),
case_statement<1>(std::cout << constant("one")),
default_statement(cout << constant("other: ") << _1)
),
cout << constant("\n")
)
);

Sincerely, Ian Yang

Sent from Shanghai, 31, China


2009/5/14 qiaojie <qia...@gmail.com>:
> 是不是还要发明一个for_each_switch 啊?

Ian Yang

unread,
May 14, 2009, 6:03:13 AM5/14/09
to pon...@googlegroups.com
继续来

std::for_each(
vs.begin(), vs.end(),
if_(_1->* &Shape::IsVisible)[
bind(&Shape::draw, _1, g)
].else_[
bind(&Shape::draw_hide, _1, g)
]
);

Sincerely, Ian Yang

Sent from Shanghai, 31, China


2009/5/14 qiaojie <qia...@gmail.com>:

qiaojie

unread,
May 14, 2009, 6:10:32 AM5/14/09
to pon...@googlegroups.com
呵呵,就是想着有人能写出这种扭曲的代码,很能说明boost的问题。

把代码写成这样,首先就毫无可读性了。但最重要的一点是,每次你写
迭代的时候就会分神去考虑用for_each怎么个写法,能想出


for_each(vs.begin(), vs.end(), if_then(bind(&shape::visible, _1) ==
true, bind(&shape::draw, _1)(graph));

这种写法,是不是觉得很有成就感?很满足C++程序员的虚荣心?这
对一个C++程序员来说有很大的诱惑性,但这恰恰是对程序设计非常
有害的习惯,一旦你沉迷于这些奇巧淫技之后,你就陷入一个误区了,
想得会是怎么把程序写的更cool,而把主要的东西抛到脑后去了。


2009/5/14 许海斌 <this...@gmail.com>:

qiaojie

unread,
May 14, 2009, 6:17:20 AM5/14/09
to pon...@googlegroups.com
恩,写的很好
充分暴露了boost的问题所在
用了boost,他就会不断的诱惑你去写这种扭曲的代码

好了,回过头来跟for代码比较一下吧,你们所标榜的
boost的简洁优雅,可读性,性能在哪里体现出来了?


2009/5/14 Ian Yang <doit...@gmail.com>:

hyifeng

unread,
May 14, 2009, 6:18:36 AM5/14/09
to TopLanguage
基本上赞同qiaojie。
不能满足 一致性、规范性、无陷阱 的特性技巧都应该剪除,除非他的相对效益很巨大。

On 5月14日, 下午6时10分, qiaojie <qiao...@gmail.com> wrote:
> 呵呵,就是想着有人能写出这种扭曲的代码,很能说明boost的问题。
>
> 把代码写成这样,首先就毫无可读性了。但最重要的一点是,每次你写
> 迭代的时候就会分神去考虑用for_each怎么个写法,能想出
> for_each(vs.begin(), vs.end(), if_then(bind(&shape::visible, _1) ==
> true, bind(&shape::draw, _1)(graph));
> 这种写法,是不是觉得很有成就感?很满足C++程序员的虚荣心?这
> 对一个C++程序员来说有很大的诱惑性,但这恰恰是对程序设计非常
> 有害的习惯,一旦你沉迷于这些奇巧淫技之后,你就陷入一个误区了,
> 想得会是怎么把程序写的更cool,而把主要的东西抛到脑后去了。
>

> 2009/5/14 许海斌 <thisis...@gmail.com>:

Ian Yang

unread,
May 14, 2009, 6:26:03 AM5/14/09
to pon...@googlegroups.com
作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。

Sincerely, Ian Yang

Sent from Shanghai, 31, China


2009/5/14 hyifeng <hyi...@gmail.com>:

up duan

unread,
May 14, 2009, 6:51:50 AM5/14/09
to pon...@googlegroups.com
void draw_all(vector<Shape*>& vs, Graphics* graph)
 {
   for (int i=0; i<vs.size(); ++i)
      if(vs[i]->IsVisible())
          vs[i]->draw(graph);
      else
          vs[i]->draw_hide(graph);
 }

这样:

namespace {
    struct Process {
        void operator()(Sharp* s, Graphics* graph) {
      if(s->IsVisible())
          s->draw(graph);
      else
          s->draw_hide(graph);
        }
    };
}

for_each(vs.begin(), vs.end(), bind2st(Process(), graph));


2009/5/14 Ian Yang <doit...@gmail.com>

up duan

unread,
May 14, 2009, 6:52:39 AM5/14/09
to pon...@googlegroups.com
我不明白这样写有什么扭曲之处。

2009/5/14 up duan <fix...@gmail.com>

qiaojie

unread,
May 14, 2009, 8:06:46 AM5/14/09
to pon...@googlegroups.com
好吧,这样不扭曲,至少我还能看的懂
不过论简洁性:你这个for_each用了8行代码,而for只要5行
论可读性:显然for更容易理解
论性能:debug版下for_each肯定差,release可能可以打个平手。

那么你现在告诉我,这里用for_each到底有什么好处?

2009/5/14 up duan <fix...@gmail.com>:

Fei Yan

unread,
May 14, 2009, 8:32:56 AM5/14/09
to pon...@googlegroups.com
我来加一个其它方面的, 如果需要做TDD的话,那么分离的代码是更易于测试和验证的,从而在工程上讲,是更容易提升质量的。

从代码的可读性上来说,我觉得是值得商榷的,二者并不一定谁的更容易理解;试想一下这样一个情况:
  假设那几行For代码夹杂在一堆凌乱、嵌套很深的垃圾代码中(我接触了不少这样的代码,来自于伟大的印度),那么我觉得如果他们把那些深入嵌套的类似的for循环拉出来,做一个functor,可读性会大大提高,维护起来也容易得多。

或者概括一点说,for_each的方式起码是减少了一重嵌套,在冗长的代码段中,少一层嵌套是会节约很多脑细胞的。曾经有一些观点认为不能用代码行的长度来判断函数是否需要重构,而是依据嵌套的层级。

我曾经遇到的一个情况是:有个印度同事在一个函数中花了130行,三重for嵌套来做一个vector内的数据的差集操作(interset),我用functor加2个STL算法,将其精简为10行不到的样子,结果代码的可读性大不一样,Review代码的人都一眼知晓我改动之后的代码是什么意思,但原来的语义,却是至少十分钟以上才可看明白。
     


2009/5/14 qiaojie <qia...@gmail.com>

LeeoNix

unread,
May 14, 2009, 8:53:36 AM5/14/09
to pon...@googlegroups.com
我不明白的是,你总想把for_each当做很万能的东西去用呢?

也得区分适用和不适用。我前面多次强调,for_each不是万金油。不是每个地方都需要。

本身for_each这个名字本身就说明了。只是单纯的遍历而已,

如果途中有判断或者直接return的,我会毫不犹豫的放弃for_each。

如果一行就能明白的语意,我会选择for_each,这样自己也方便,也方便别人阅读。

2009/5/14 qiaojie <qia...@gmail.com>

qiaojie

unread,
May 14, 2009, 9:08:21 AM5/14/09
to pon...@googlegroups.com
因为之前有很多人在说for_each代替for的好处,说for_each怎么优雅怎么简洁。
于是我就感觉非常奇怪,C++在没有lambda特性的支持下,怎么能写出优雅
的for_each代码来?我需要好好学习一下。
然后结果大家也看到了,除了B.S.举的那个例子稍微正常一点之外,遇到稍
微复杂一点的情况就只能用扭曲而丑陋的代码来实现了。


2009/5/14 LeeoNix <leeo...@gmail.com>:

许海斌

unread,
May 14, 2009, 9:48:32 AM5/14/09
to TopLanguage
所以这种情形建议你可以放弃for_each,effective stl item47说的差不多也是这个道理,如LeeoNix所说,只要
for_each解决了20%的问题,就是一个很有用的函数。还有借助于boost库中的新式迭代器中的迭代器模板filter_iterator应该
也可以解决这个问题,相信会优雅很多,只是我没怎么仔细研究过这个东西,有兴趣的朋友可以试试

On 5月14日, 下午6时10分, qiaojie <qiao...@gmail.com> wrote:

> 呵呵,就是想着有人能写出这种扭曲的代码,很能说明boost的问题。
>
> 把代码写成这样,首先就毫无可读性了。但最重要的一点是,每次你写
> 迭代的时候就会分神去考虑用for_each怎么个写法,能想出
> for_each(vs.begin(), vs.end(), if_then(bind(&shape::visible, _1) ==
> true, bind(&shape::draw, _1)(graph));
> 这种写法,是不是觉得很有成就感?很满足C++程序员的虚荣心?这
> 对一个C++程序员来说有很大的诱惑性,但这恰恰是对程序设计非常
> 有害的习惯,一旦你沉迷于这些奇巧淫技之后,你就陷入一个误区了,
> 想得会是怎么把程序写的更cool,而把主要的东西抛到脑后去了。
>

> 2009/5/14 许海斌 <thisis...@gmail.com>:


>
>
>
>
>
> > 这种情况大致可以考虑放弃for_each了,我觉得for_each在很多情况下可以让我们的程序更加简洁但不是全部,如果非要写的话
> > for_each + bind + lambda大致如下吧
>
> > for_each(vs.begin(), vs.end(), if_then(bind(&shape::visible, _1) ==
> > true, bind(&shape::draw, _1)(graph));
>
> > On 5月14日, 下午5时31分, up duan <fixo...@gmail.com> wrote:
> >> 2009/5/14 qiaojie <qiao...@gmail.com>
>
> >> > 我只想知道这个例子你用for_each怎么写?
> >> > 难道这个例子很过分,很特殊吗?
>
> >> 我不知道用for_each写有什么问题。
> >> 一点都不特殊,显然,for的{}可以直接使用context,而for_each需要参数传递进去,你觉得不能传递进去么?bind就可以把参数传进去了呀。

> >> 以后,如果C++的lambda引入[graph](it){这儿可以直接使用graph},就不在需要这么多辅助设施搞定了。- 隐藏被引用文字 -
>
> - 显示引用的文字 -

wangmao

unread,
May 14, 2009, 9:49:02 AM5/14/09
to pon...@googlegroups.com
for_each代替for用得合适的时候自然非常优雅非常简洁。用得不合适的时候自然说有多烂就有多烂。qiaojie你的话让我想起了几年前有人发现新大陆说原来python比c++要快得多。代码优雅与否是取决于写代码的人的。就象有些人说可以用c写出面向对象的程序一样,关键在于人,而非工具,工具只是起了个辅助作用。
2009/5/14 qiaojie <qia...@gmail.com>

许海斌

unread,
May 14, 2009, 9:56:46 AM5/14/09
to TopLanguage
不过我觉得花个三个小时学习下boost::lambda就不会觉得这个代码有什么扭曲的了,for_each不是8行,一行就够了,项目组里每个成员
花个三个小时学习时间的代价得到大家都看得懂的简洁优雅的代码,还是值得的。


On 5月14日, 下午8时06分, qiaojie <qiao...@gmail.com> wrote:
> 好吧,这样不扭曲,至少我还能看的懂
> 不过论简洁性:你这个for_each用了8行代码,而for只要5行
> 论可读性:显然for更容易理解
> 论性能:debug版下for_each肯定差,release可能可以打个平手。
>
> 那么你现在告诉我,这里用for_each到底有什么好处?
>

> 2009/5/14 up duan <fixo...@gmail.com>:
>
>
>
> > 我不明白这样写有什么扭曲之处。
>
> > 2009/5/14 up duan <fixo...@gmail.com>


>
> >> void draw_all(vector<Shape*>& vs, Graphics* graph)
> >> {
> >> for (int i=0; i<vs.size(); ++i)
> >> if(vs[i]->IsVisible())
> >> vs[i]->draw(graph);
> >> else
> >> vs[i]->draw_hide(graph);
> >> }
> >> 这样:
> >> namespace {
> >> struct Process {
> >> void operator()(Sharp* s, Graphics* graph) {
> >> if(s->IsVisible())
> >> s->draw(graph);
> >> else
> >> s->draw_hide(graph);
> >> }
> >> };
> >> }
> >> for_each(vs.begin(), vs.end(), bind2st(Process(), graph));
>

> >> 2009/5/14 Ian Yang <doit....@gmail.com>
>
> >>> 作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库-只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。


>
> >>> Sincerely, Ian Yang
>
> >>> Sent from Shanghai, 31, China
>

> >>> 2009/5/14 hyifeng <hyif...@gmail.com>:


> >>> > 基本上赞同qiaojie。
> >>> > 不能满足 一致性、规范性、无陷阱 的特性技巧都应该剪除,除非他的相对效益很巨大。
>
> >>> > On 5月14日, 下午6时10分, qiaojie <qiao...@gmail.com> wrote:
> >>> >> 呵呵,就是想着有人能写出这种扭曲的代码,很能说明boost的问题。
>
> >>> >> 把代码写成这样,首先就毫无可读性了。但最重要的一点是,每次你写
> >>> >> 迭代的时候就会分神去考虑用for_each怎么个写法,能想出
> >>> >> for_each(vs.begin(), vs.end(), if_then(bind(&shape::visible, _1) ==
> >>> >> true, bind(&shape::draw, _1)(graph));
> >>> >> 这种写法,是不是觉得很有成就感?很满足C++程序员的虚荣心?这
> >>> >> 对一个C++程序员来说有很大的诱惑性,但这恰恰是对程序设计非常
> >>> >> 有害的习惯,一旦你沉迷于这些奇巧淫技之后,你就陷入一个误区了,
> >>> >> 想得会是怎么把程序写的更cool,而把主要的东西抛到脑后去了。
>
> >>> >> 2009/5/14 许海斌 <thisis...@gmail.com>:
>
> >>> >> > 这种情况大致可以考虑放弃for_each了,我觉得for_each在很多情况下可以让我们的程序更加简洁但不是全部,如果非要写的话
> >>> >> > for_each + bind + lambda大致如下吧
>
> >>> >> > for_each(vs.begin(), vs.end(), if_then(bind(&shape::visible, _1) ==
> >>> >> > true, bind(&shape::draw, _1)(graph));
>
> >>> >> > On 5月14日, 下午5时31分, up duan <fixo...@gmail.com> wrote:
> >>> >> >> 2009/5/14 qiaojie <qiao...@gmail.com>
>
> >>> >> >> > 我只想知道这个例子你用for_each怎么写?
> >>> >> >> > 难道这个例子很过分,很特殊吗?
>
> >>> >> >> 我不知道用for_each写有什么问题。
>
> >>> >> >> 一点都不特殊,显然,for的{}可以直接使用context,而for_each需要参数传递进去,你觉得不能传递进去么?bind就可以把参数传进去了呀。

missdeer

unread,
May 14, 2009, 9:58:35 AM5/14/09
to TopLanguage
不是代码行数少就是简洁了,还是那个极端的无理例子,一个程序只有一个main函数,是不是最简洁的。
说到可读性,我窃以为也许是因为你已经用了十几年for了,而对于for_each+boost的搭配则是基于你曾经可能花过两三个小时的了解以及这两
天在这里的口水仗,自然看for要顺眼一些。
最后说性能,要比性能debug肯定不能纳入考虑的范围,而release,你也只是说"可能",说实话我也没真实测过,不过一直以来那些教科书上都说
for_each如果搭配functor可以在线展开从而省掉一个函数调用的开销,我所知道的仅止于此。

On May 14, 8:06 pm, qiaojie <qiao...@gmail.com> wrote:
> 好吧,这样不扭曲,至少我还能看的懂
> 不过论简洁性:你这个for_each用了8行代码,而for只要5行
> 论可读性:显然for更容易理解
> 论性能:debug版下for_each肯定差,release可能可以打个平手。
>
> 那么你现在告诉我,这里用for_each到底有什么好处?
>

> 2009/5/14 up duan <fixo...@gmail.com>:
>
>
>
>
>
> > 我不明白这样写有什么扭曲之处。
>
> > 2009/5/14 up duan <fixo...@gmail.com>
>

> >> void draw_all(vector<Shape*>& vs, Graphics* graph)
> >> {
> >> for (int i=0; i<vs.size(); ++i)
> >> if(vs[i]->IsVisible())
> >> vs[i]->draw(graph);
> >> else
> >> vs[i]->draw_hide(graph);
> >> }
> >> 这样:
> >> namespace {
> >> struct Process {
> >> void operator()(Sharp* s, Graphics* graph) {
> >> if(s->IsVisible())
> >> s->draw(graph);
> >> else
> >> s->draw_hide(graph);
> >> }
> >> };
> >> }
> >> for_each(vs.begin(), vs.end(), bind2st(Process(), graph));
>

> >> 2009/5/14 Ian Yang <doit....@gmail.com>
>
> >>> 作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库 只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。


>
> >>> Sincerely, Ian Yang
>
> >>> Sent from Shanghai, 31, China
>

> >>> 2009/5/14 hyifeng <hyif...@gmail.com>:

qiaojie

unread,
May 14, 2009, 10:10:49 AM5/14/09
to pon...@googlegroups.com
2009/5/14 wangmao <lwm...@gmail.com>:
> for_each代替for用得合适的时候自然非常优雅非常简洁。用得不合适的时候自然说有多烂就有多烂。

我不知道你这话是指什么?

对于这段代码


for (int i=0; i<vs.size(); ++i)
if(vs[i]->IsVisible())
vs[i]->draw(graph);
else
vs[i]->draw_hide(graph);

你是想说这段代码可以用for_each实现的很优雅呢?还是想说for_each只适用于for_each(first, last,
mem_fun(&Shape::draw);这样的简单情况才能显得优雅?
如果是前者的话,目前为止我还没看到一个优雅的for_each实现,如果是后者的话说了等于没说,我们不是在写hello
world程序,如果for_each不能用于代替一般的非平凡的for代码,那就根本不要拿for_each跟for去做比较。

qiaojie

unread,
May 14, 2009, 10:34:59 AM5/14/09
to pon...@googlegroups.com
2009/5/14 许海斌 <this...@gmail.com>:

> 不过我觉得花个三个小时学习下boost::lambda就不会觉得这个代码有什么扭曲的了,for_each不是8行,一行就够了,项目组里每个成员
> 花个三个小时学习时间的代价得到大家都看得懂的简洁优雅的代码,还是值得的。
>

看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用boost::lambda的话,你的项目一定会出问题。

我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。

我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误的C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少人会愿意提及boost了。

许海斌

unread,
May 14, 2009, 10:47:37 AM5/14/09
to TopLanguage
呵呵,看来不仅仅是boost错了,c++也错了

On 5月14日, 下午10时34分, qiaojie <qiao...@gmail.com> wrote:
> 2009/5/14 许海斌 <thisis...@gmail.com>:


>
> > 不过我觉得花个三个小时学习下boost::lambda就不会觉得这个代码有什么扭曲的了,for_each不是8行,一行就够了,项目组里每个成员
> > 花个三个小时学习时间的代价得到大家都看得懂的简洁优雅的代码,还是值得的。
>

> 看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用bo-ost::lambda的话,你的项目一定会出问题。


>
> 我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。
>

> 我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵-营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误的-C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少人会-愿意提及boost了。

> >> >>> 作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库--只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。

> >> - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -

qiaojie

unread,
May 14, 2009, 10:48:16 AM5/14/09
to pon...@googlegroups.com
> 最后说性能,要比性能debug肯定不能纳入考虑的范围,而release,你也只是说"可能",说实话我也没真实测过,不过一直以来那些教科书上都说
> for_each如果搭配functor可以在线展开从而省掉一个函数调用的开销,我所知道的仅止于此。

这里的性能问题非常的复杂,因为会产生2个临时对象,要看编译器是怎么实现的。
如果写成


std::for_each(
vs.begin(), vs.end(),
if_(_1->* &Shape::IsVisible)[
bind(&Shape::draw, _1, g)
].else_[
bind(&Shape::draw_hide, _1, g)
]
);

那更是无从得知会遭受多少性能上的惩罚,你根本不知道编译产生了多少临时对象,
已经会造成什么性能影响。除非去深入的了解boost::lambda的实现,并且非常了解
编译器的优化机制。这也是从另一方面,由引入高级语法糖带来的思考负担。如果
是关键性能代码段的话,绝对不能这么写。

许海斌

unread,
May 14, 2009, 11:00:45 AM5/14/09
to TopLanguage
还有你没有仔细看我的回复,你说的这种情况

void draw_all(vector<Shape*>& vs, Graphics* graph)
{
for (int i=0; i<vs.size(); ++i)
if(vs[i]->IsVisible())
vs[i]->draw(graph);
else
vs[i]->draw_hide(graph);
}
我前面说了首先是建议你放弃使用for_each,因为for_each通常是用来减少一层循环嵌套的,而你这里除了循环还有一个if判断,当然,项目
组里如果都对boost::lambda比较熟悉的话用for_each一句话解决也是可以的,这个毕竟不是什么非常扭曲的代码,对于熟悉
boost::lambda的人来说,可读性还是很高的
for_each(区间起点,区间尾部,if_then(条件,表达式));
上面的语法很复杂么?

On 5月14日, 下午10时34分, qiaojie <qiao...@gmail.com> wrote:
> 2009/5/14 许海斌 <thisis...@gmail.com>:
>

> > 不过我觉得花个三个小时学习下boost::lambda就不会觉得这个代码有什么扭曲的了,for_each不是8行,一行就够了,项目组里每个成员
> > 花个三个小时学习时间的代价得到大家都看得懂的简洁优雅的代码,还是值得的。
>

> 看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用bo-ost::lambda的话,你的项目一定会出问题。


>
> 我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。
>

> 我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵-营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误的-C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少人会-愿意提及boost了。
>
>
>
>
>

> >> >>> 作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库--只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。

> >> - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -

Ian Yang

unread,
May 14, 2009, 11:38:50 AM5/14/09
to pon...@googlegroups.com
取其精华,去其糟粕


1) Boost有严格的审核制度,保证的代码的质量。并且审核对设计、文档、代码实现、后期维护都有严格要求。

2)Boost有良好的跨平台性,能兼容多种主流编译器。这种活基本没什么技术含量,就是反复测试,总结各编译器的差异,然后分别处理。自己来做的话是非常烦人的。

3)Boost的复杂性主要在于实现,对用户的接口还是很简洁的,比如tuple。接口就是加强版的std::pair.

4)如果要做泛型编程,Boost绝对是必备库,像MPL, enable_if, type_traits这些泛型的基本工具。


5)Boost的库很多是非倾入式的,基本类型和c++标准库直接支持,用户类满足一些concept的requirements也能直接用,不满足也能通过traits类特化。

6)Boost一些库在完成它本身目的方面几乎做到极致了,比如Boost.Function.
个人认为Boost.Function是很有用的,可以运行时更改行为,并且让Boost.Function的调用都和Function包装的Invokable对象松耦合。典型应用:Listener.

使用Boost应该根据需要,选择性的使用。也不是说用的for就要用for_each+boost.lambda。但是有些时候:
1)你程序中使用了一些函数指针,替换成boost.function可能会让你的程序更灵活。
2)写多线程,boost.thread提供了一个轻量的跨平台方案
3)还有很多在特定领域的库:像regex正则表达式,string algo对字符串的各种算法等等。

另外像asio在设计,实现都做得非常优秀,不用学习学习也不错。bimap还提供了详细的设置演化,图文并茂。

当然任何东西都不是完美的,Boost也用很多硬伤,刚上我写boost.lambda的时候测试了一下,写错了一个地方,出来的编译错误直接跳到了boost某个深层的头文件中。Boost通过template使得库非常灵活、通用,但是缺少语言级别的支持,这些缺点也是无法避免的。就像STL,成了标准也是骂的人一大堆。

另外Boost是个库集合,每个库都有自己鲜明的目的,lambda的更重要的意思在于,当你需要这个玩意的时候,拿来用就好。

写这些不是为了说服别人去使用boost,有人批评Boost也不会影响我对Boost的喜爱。萝卜青菜各有所爱,我就晒晒我对Boost的认识和一些使用经验而已。

qiaojie

unread,
May 14, 2009, 12:02:31 PM5/14/09
to pon...@googlegroups.com
这篇帖子还是有些真知灼见的。boost毕竟是C++专家们开发的,一无是处是不可能的,其实我也很希望听到大家谈谈boost
在实际工程中的使用心得,如果有好的东西,我是不会排斥的。

2009/5/14 Ian Yang <doit...@gmail.com>:

峰郭

unread,
May 14, 2009, 3:47:31 AM5/14/09
to pon...@googlegroups.com
一句话,好用就用,不好用就用别的,别的也不好用,那么就自己写好用的。

2009/5/14 qiaojie <qia...@gmail.com>
2009/5/14 up duan <fix...@gmail.com>:
>
>
> 2009/5/14 Ian Yang <doit...@gmail.com>
>>
>> 觉得C++的库难流行有个很重要的原因是:用C++的开发者似乎对第三方库都很不信任,更情愿自己写一个。

>>
>> Sincerely, Ian Yang
>>
>> Sent from Shanghai, 31, China
>
> 照我的看法,这只是一个结果,而不是一个原因。
> 为什么Javaer对Java库能够信任C#er对.NET库能够信任,而C++er对C++库不能信任?因为他们可挑选的太多了,他们能看透实现的太多了,所以他们会觉得自己也可以而且完全应该自己实现一个。
> 当然,他们之所以能看透,能挑选,也是因为大多数C++库大多数都是一个小小的抽象也实现,都没有到达Java库和.net库那种庞大和平台级别。这种现象的一个原因我前面说过:C++不是一个平台,只是一个语言。另一个原因就是历史,那时候人们总是提供细粒度的组件以供重用,跟现在的趋势不同,现在是倾向于提供越来越大的组件。这个趋势跟人们对计算机的期望值越来越高有密切的关系,现在的计算机承载着人类生产力【本来想说人类文明的,觉得太大了点:)】的很大的一部分,要执行越来越庞大越来越复杂的任务,所以,基础组件个头大一点才好掌控,才好控制复杂度。
> 基于这些理由,C++程序员倾向于自己实现库,就算自己不实现,也倾向于看透别人库的实现。比如:qiaojie就用看透C++库如此费神儿批判C++,我觉得他可能从来没有试图去看透过.net库的实现:)。


我没有全面批判C++,事实上我仍然会有一半的工作基于C++来开发,我只是针对某些库滥用C++的情况做一些批判,
C++很灵活用法很多,用好用坏千差万别,这个在其他语言里是非常少见的,所以有争议也是非常正常的。

另外,对 .net的底层实现机制我也很有兴趣啊,用C++/CLI的话会比较注重这方面。

OxFAN

unread,
May 14, 2009, 6:35:57 AM5/14/09
to pon...@googlegroups.com
有任何迹象表明boost要适用于所有的c++程序么?
STL尚且都做不到!!!
2009/5/14 qiaojie <qia...@gmail.com>
boost跟STL一样是个基础库,很多基础组件都是为了通用程序而写的,所以如果要用的话,肯定是适合几乎所有C++程序的,不存在你说的需求问题,所以不要偷换概念,大谈什么适用性的问题。boost花了那么大力气,动用了各种奇巧淫技去模拟那些高级语言的特性,典型的高射炮打蚊子,我不知道这能提高多少软件生产力,但是由此带来的问题是显而易见的,这不是个人喜好问题,而是一个事实。





2009/5/14 OxFAN <oday...@gmail.com>:
> 很多人都在说这个库哪里哪里不行,说那个库哪里哪里不行,但没见人给出一个“可行”的方案的。
> 更何况,这些被提出来的“缺点”,没有任何有力的证据证明他们真的是设计缺陷。
> 如果你使用一个库之前连自己的需求和这个库是否适合你的需求都不清楚,那么在此基础上的任何评价都是没有意义的。如果它适合,那么就用它,如果不适合,那就不要用,并且第二种情况很正常也很普遍,然后你只要去寻找更合适的就行了,而不应该在公共场合披露这个库所谓的“缺点”。
> 任何语言、库、系统都有它适用的地方,没有什么是完美的,不可能满足每个人的爱好,单纯的根据个人喜好来评判这个那个,说白了是浪费所有人的时间。
>
> 还有,看到前面有人又把别的语言扔出来了,就像c++之父说的那样,任何将其他语言与c++的比较都是没有意义的,因为基本没有公平的比较。

OxFAN

unread,
May 14, 2009, 6:49:42 AM5/14/09
to pon...@googlegroups.com
不是不信任,而是c++没有把某些库作为语言的一部分。
java  .net提供语言特性的同时也绑定了自己的标准库,java和.net的程序员几乎不需要什么第三方库就可以做出整个应用程序。
c++一直没有强迫程序员使用某些库,像STL等的库还有许多版本,选择很多。
c++赋予程序员尽可能多的自由(不是无限多)。

同时回应qiaojie的“奇巧淫技”,就算有人写不好的丑陋的代码,那也是个人喜好,没有讨论价值。
所谓就事论事,最终还是回到人的问题上了。

Jack.Chu

unread,
May 14, 2009, 11:27:03 AM5/14/09
to TopLanguage
我颇为赞同boost不应该提倡使用。

因为最重要、最实用的基本算法和容器已经被包含在STL里了,boost只能从不那么被广泛应用的地方着手。这就导致了boost虽然名声在外,却是叫
好不叫座的场面。

另外像是lambda,tuple,for_each,如果不在C++规范中定义,用各种奇技淫巧来在语法层实现,注定了只能是小众的东西。非规范和非
必要的东西,不是标准里的东西,就已经是弃之不用的很好的理由了。而且就我的感觉,C++语法中缺乏lambda表达式,那么应用for_each这样
的东西就如同鸡肋一样。boost::lambda实在是很令人作呕的写法。


On 5月14日, 下午10时34分, qiaojie <qiao...@gmail.com> wrote:
> 2009/5/14 许海斌 <thisis...@gmail.com>:
>

LeeoNix

unread,
May 14, 2009, 1:58:45 PM5/14/09
to pon...@googlegroups.com
for_each有很多地方用起来是很有意义的。
 
比如析构的时候将某些存在表里的内容删除掉。用for_each方便无比。
 
拿到手一个同事以前写的代码,三个容器的内容调用release函数,几乎一模一样的三个for循环。
 
接手之后,顺手就把这三个修改为for_each了,能够一眼就让人看明白是清理内容的。
 
如果boost能够精炼几个最常用最意义的功能的话就好了。所谓boost精简版。
 
share_ptr我是自己实现的,纯粹的计数,没有弱指针。
 
我还是提倡团队优先。如果是带的小弟,教会他,利人利己。
 
不过,最近带的几个小弟有些不尽人意。唉……

2009/5/14 qiaojie <qia...@gmail.com>

许海斌

unread,
May 14, 2009, 7:00:12 PM5/14/09
to TopLanguage
我确实是大量使用boost::lambda,但是通常限于如下代码

for (;;) {
thread::sleep(get_system_time() +
setting_.heart_beat_scan_interval);
LOG4CXX_TRACE(logger, boost::format("%1% [%2%:%3%] Begin to
scan ...")
% asio_server_->get_description() % asio_server_->get_addr
() % asio_server_->get_port());
for_each(sessions_.begin(), sessions_.end(), bind
(&session::heart_beat, _1, heart_beat_buff));
}

因为我觉得比下面的代码

for (;;) {
thread::sleep(get_system_time() +
setting_.heart_beat_scan_interval);
LOG4CXX_TRACE(logger, boost::format("%1% [%2%:%3%] Begin to
scan ...")
% asio_server_->get_description() % asio_server_->get_addr
() % asio_server_->get_port());
for (vector<sessions_ptr>::iterator iter = sessions_.begin();
iter != sessions_.end(); ++sessions_) {
(*iter)->heart_beat(heart_beat_buff);
}
}

好看多了

On 5月14日, 下午10时34分, qiaojie <qiao...@gmail.com> wrote:
> 2009/5/14 许海斌 <thisis...@gmail.com>:
>

> > 不过我觉得花个三个小时学习下boost::lambda就不会觉得这个代码有什么扭曲的了,for_each不是8行,一行就够了,项目组里每个成员
> > 花个三个小时学习时间的代价得到大家都看得懂的简洁优雅的代码,还是值得的。
>

> 看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用bo-ost::lambda的话,你的项目一定会出问题。


>
> 我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。
>

> 我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵-营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误的-C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少人会-愿意提及boost了。
>
>
>
>
>

> >> >>> 作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库--只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。

> >> - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -

许海斌

unread,
May 14, 2009, 7:30:00 PM5/14/09
to TopLanguage
我觉得使用c++的人可以分两种,一种是库开发者,还有一种是应用程序开发者,如果说程序库开发者使用了各种奇技淫巧实现了高级语言的一些特性让应用程
序开发者能够以简洁优雅的格式撰写c++程序的话那也无可厚非的,毕竟程序库的主要目的是提供给大家使用的,而不是用来看的,就算看的不爽用的爽就行
了,毕竟全世界需要看这些代码并且维护的也就那么几个人,而使用的人确是成千上万的,不应该提倡使用的是loki这样的程序库而不是boost,提倡实
用至上的朋友可以看看boost::multi_index、boost::python、boost::string_algo、
boost::circular_buffer等等,这些可能会比较满足你的胃口,虽然众口难调,但是毕竟boost中有七八十个程序库,相信还是能找
到一些你想要的东西,一棒子打死,那也太可惜了。

上次看到有人说boost中template用的有点泛滥了,我到不觉得,毕竟boost不是一般的应用程序而是程序库,为了兼顾效率以及通用性基本上
都是不得不用template,代码看起来确实不够通俗易懂,但是用的爽就行了,当然有人也许会说用的也不爽,基本上都是因为连帮助文档也没怎么看过,
如果boost中到处充斥着virtual,相信骂得人更多。


On 5月14日, 下午11时27分, "Jack.Chu" <working...@gmail.com> wrote:
> 我颇为赞同boost不应该提倡使用。
>
> 因为最重要、最实用的基本算法和容器已经被包含在STL里了,boost只能从不那么被广泛应用的地方着手。这就导致了boost虽然名声在外,却是叫
> 好不叫座的场面。
>
> 另外像是lambda,tuple,for_each,如果不在C++规范中定义,用各种奇技淫巧来在语法层实现,注定了只能是小众的东西。非规范和非
> 必要的东西,不是标准里的东西,就已经是弃之不用的很好的理由了。而且就我的感觉,C++语法中缺乏lambda表达式,那么应用for_each这样
> 的东西就如同鸡肋一样。boost::lambda实在是很令人作呕的写法。
>
> On 5月14日, 下午10时34分, qiaojie <qiao...@gmail.com> wrote:
>
>
>
> > 2009/5/14 许海斌 <thisis...@gmail.com>:
>
> > > 不过我觉得花个三个小时学习下boost::lambda就不会觉得这个代码有什么扭曲的了,for_each不是8行,一行就够了,项目组里每个成员
> > > 花个三个小时学习时间的代价得到大家都看得懂的简洁优雅的代码,还是值得的。
>

> > 看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用bo-ost::lambda的话,你的项目一定会出问题。


>
> > 我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。
>

> > 我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵-营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误的-C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少人会-愿意提及boost了。
>

> > >> >>> 作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库--只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。

> > >> - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -

Eric.Wang

unread,
May 14, 2009, 8:47:51 PM5/14/09
to TopLanguage
我更喜欢以下的代码:

while (true)
{
int sec = get_system_time() + setting_.heart_beat_scan_interval;
thread::sleep(sec);

string log = boost::format("%1% [%2%:%3%] Begin to scan ...") %


asio_server_->get_description() % asio_server_->get_addr() %
asio_server_->get_port());

LOG4CXX_TRACE(logger, log);

for (vector<sessions_ptr>::iterator iter = sessions_.begin(); iter !
= sessions_.end(); ++sessions_)
{

sessions_ptr sp = *it;
sp->heart_beat(heart_beat_buff);
}
}

我这样写的代码,只要是智商60以上的大四学生就能阅读我的代码。

vector<sessions_ptr>::iterator iter = sessions_.begin()是这块代码最丑陋的地方,没办法,
要到C++0x才有auto it = sessions_.begin()这种写法。

像你那样运算和调用堆一块的代码,怎么写都是难看的。要在我们公司,肯定要被批倒批臭了。

for_each(sessions_.begin(), sessions_.end(), bind
(&session::heart_beat, _1, heart_beat_buff)); 比如这行代码,如果以后修改的时候想给每个item多
做一点事情怎么办?写的人爽了,维护的人惨了。

Eric.Wang

unread,
May 14, 2009, 8:59:48 PM5/14/09
to TopLanguage

对于那130行代码,我宁愿加一行注释,或者封装一个单独的函数。10行的代码未必就比130行的代码容易读。

用for_each()来release东西,正是我反对的用法。写一堆的functor很好看么?看到 for_each(it.begin(),
it.end(), Free_Resource_Functor())我不是不还要去看看Free_Resource_Functor都做了些什
么?

for (it = vector.begin; it != vector.end(); it++)
{
obj* p = (*it);
p->detach_from(this);
p->stop();
delete p;
}
vector.clear();

这样不是更清爽吗?以后修改起来也方便。


On 5月14日, 下午8时32分, Fei Yan <skyscribe...@gmail.com> wrote:
> 我来加一个其它方面的, 如果需要做TDD的话,那么分离的代码是更易于测试和验证的,从而在工程上讲,是更容易提升质量的。
>
> 从代码的可读性上来说,我觉得是值得商榷的,二者并不一定谁的更容易理解;试想一下这样一个情况:
> 假设那几行For代码夹杂在一堆凌乱、嵌套很深的垃圾代码中(我接触了不少这样的代码,来自于伟大的印度),那么我觉得如果他们把那些深入嵌套的类似的for循环拉出来,做一个functor,可读性会大大提高,维护起来也容易得多。
>
> 或者概括一点说,for_each的方式起码是减少了一重嵌套,在冗长的代码段中,少一层嵌套是会节约很多脑细胞的。曾经有一些观点认为不能用代码行的长度来判断函数是否需要重构,而是依据嵌套的层级。
>
> 我曾经遇到的一个情况是:有个印度同事在一个函数中花了130行,三重for嵌套来做一个vector内的数据的差集操作(interset),我用functor加2个STL算法,将其精简为10行不到的样子,结果代码的可读性大不一样,Review代码的人都一眼知晓我改动之后的代码是什么意思,但原来的语义,却是至少十分钟以上才可看明白。
>

> 2009/5/14 qiaojie <qiao...@gmail.com>


>
> > 好吧,这样不扭曲,至少我还能看的懂
> > 不过论简洁性:你这个for_each用了8行代码,而for只要5行
> > 论可读性:显然for更容易理解
> > 论性能:debug版下for_each肯定差,release可能可以打个平手。
>
> > 那么你现在告诉我,这里用for_each到底有什么好处?
>

> > 2009/5/14 up duan <fixo...@gmail.com>:
> > > 我不明白这样写有什么扭曲之处。
>
> > > 2009/5/14 up duan <fixo...@gmail.com>
>

> > >> void draw_all(vector<Shape*>& vs, Graphics* graph)
> > >> {
> > >> for (int i=0; i<vs.size(); ++i)
> > >> if(vs[i]->IsVisible())
> > >> vs[i]->draw(graph);
> > >> else
> > >> vs[i]->draw_hide(graph);
> > >> }
> > >> 这样:
> > >> namespace {
> > >> struct Process {
> > >> void operator()(Sharp* s, Graphics* graph) {
> > >> if(s->IsVisible())
> > >> s->draw(graph);
> > >> else
> > >> s->draw_hide(graph);
> > >> }
> > >> };
> > >> }
> > >> for_each(vs.begin(), vs.end(), bind2st(Process(), graph));
>

> > >> 2009/5/14 Ian Yang <doit....@gmail.com>


>
> > 作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。
>
> > >>> Sincerely, Ian Yang
>
> > >>> Sent from Shanghai, 31, China
>

> > >>> 2009/5/14 hyifeng <hyif...@gmail.com>:

up duan

unread,
May 14, 2009, 9:00:51 PM5/14/09
to pon...@googlegroups.com


2009/5/14 qiaojie <qia...@gmail.com>

好吧,这样不扭曲,至少我还能看的懂
不过论简洁性:你这个for_each用了8行代码,而for只要5行
论可读性:显然for更容易理解
论性能:debug版下for_each肯定差,release可能可以打个平手。

那么你现在告诉我,这里用for_each到底有什么好处?

还是我前面说的:for自由而灵活,for_each强迫你考虑清楚处理跟数据之间的接口。自由灵活的优势就不说了,劣势就是:如果{}里面也就是处理繁复的话,影响可理解性。而for_each却提供了一个name的机会,这样提供了一个间接层和一个抽象的机会,也就有了复用处理的可能性。
所以,for适应于轻型的不需要复用的简单环境,属于相对轻型的方法。而for_each却适应于比较繁复需要更抽象一些的环境,属于重型方法。
我并没有说谁更好谁更不好,只是说for_each正在逐渐流行,尤其是一旦lambda出现,for_each的劣势得以避免,优势就更明显了。

Eric.Wang

unread,
May 14, 2009, 9:04:34 PM5/14/09
to TopLanguage
你这里for_each有个矛盾:
1、"处理繁复的话,影响可理解性"
2、"提供了一个间接层和一个抽象的机会"

for_each既然不适合处理复杂的事务,那么还抽象什么,搞什么中间层?for_each就是一颗难吃的语法糖。


On 5月15日, 上午9时00分, up duan <fixo...@gmail.com> wrote:
> 2009/5/14 qiaojie <qiao...@gmail.com>
>

up duan

unread,
May 14, 2009, 9:09:30 PM5/14/09
to pon...@googlegroups.com
看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用boost::lambda的话,你的项目一定会出问题。

我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。

我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误的C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少人会愿意提及boost了。

我看到满纸“结论”。一些“预言”。一些“事实”。
我需要证据。
因为对我来说,Boost库带了一个好头而不是坏头。你所谓的错误的C++价值观是指?或许是指不断地使用语言特性实现可有可无的重用?我怎么觉得这很正常呢?C#的foreach和lambda的实现你考察过么?C++的实现不过就是C++语言自己实现的,由于你能直接看到,你就不满意了,你就要不使用了?就要指责C++的错误价值观了?

up duan

unread,
May 14, 2009, 9:14:31 PM5/14/09
to pon...@googlegroups.com


2009/5/14 qiaojie <qia...@gmail.com>

> 最后说性能,要比性能debug肯定不能纳入考虑的范围,而release,你也只是说"可能",说实话我也没真实测过,不过一直以来那些教科书上都说
> for_each如果搭配functor可以在线展开从而省掉一个函数调用的开销,我所知道的仅止于此。

这里的性能问题非常的复杂,因为会产生2个临时对象,要看编译器是怎么实现的。
如果写成
 std::for_each(
      vs.begin(), vs.end(),
      if_(_1->* &Shape::IsVisible)[
          bind(&Shape::draw, _1, g)
      ].else_[
          bind(&Shape::draw_hide, _1, g)
      ]
  );
那更是无从得知会遭受多少性能上的惩罚,你根本不知道编译产生了多少临时对象,
已经会造成什么性能影响。除非去深入的了解boost::lambda的实现,并且非常了解
编译器的优化机制。这也是从另一方面,由引入高级语法糖带来的思考负担。如果
是关键性能代码段的话,绝对不能这么写。


我们是在说for_each跟for的关系,而不是for_each怎么取代for + if else之类的。你不能指望所有的代码都用for_each的处理参数搞定, 毕竟,最合理的方式是for_each的处理参数提供了抽象的机会,不要为了简洁阉割自己的能力,那样其实就退化为for了。而且,如果lambda出现了,for_each确实可能无代价的退化为for。

许海斌

unread,
May 14, 2009, 9:15:02 PM5/14/09
to TopLanguage
如你所说的话,其实把vector换成数组更好,这样连从来没学过c++的c程序员也能看到懂了,不用大四,大一大二的学生都能看懂了

> > > 看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用bo--ost::lambda的话,你的项目一定会出问题。


>
> > > 我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。
>

> > > 我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵--营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误-的-C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少-人会-愿意提及boost了。

> > > >> >>> 作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库---只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。

up duan

unread,
May 14, 2009, 9:19:37 PM5/14/09
to pon...@googlegroups.com


2009/5/15 Eric.Wang <wangsh...@gmail.com>


对于那130行代码,我宁愿加一行注释,或者封装一个单独的函数。10行的代码未必就比130行的代码容易读。

用for_each()来release东西,正是我反对的用法。写一堆的functor很好看么?看到 for_each(it.begin(),
it.end(), Free_Resource_Functor())我不是不还要去看看Free_Resource_Functor都做了些什
么?

for (it = vector.begin; it != vector.end(); it++)
{
 obj* p = (*it);
 p->detach_from(this);
 p->stop();
 delete p;
}
vector.clear();

这样不是更清爽吗?以后修改起来也方便。

哦,看开你的脑容量和智商都很高。我不知道模块化对你有什么益处,真的。

up duan

unread,
May 14, 2009, 9:21:12 PM5/14/09
to pon...@googlegroups.com


2009/5/15 Eric.Wang <wangsh...@gmail.com>

你这里for_each有个矛盾:
1、"处理繁复的话,影响可理解性"
2、"提供了一个间接层和一个抽象的机会"

for_each既然不适合处理复杂的事务,那么还抽象什么,搞什么中间层?for_each就是一颗难吃的语法糖。

我可没有说for_each不适合处理复杂的事务吧,你整个把我的意思给弄拧了。我说for不适合处理复杂的事物,因为它把所有的东西都平摊在一个地方了。

up duan

unread,
May 14, 2009, 9:22:43 PM5/14/09
to pon...@googlegroups.com
看来我还得再copy一遍:

直接把我在另一个线索里发的帖子copy过来:)

for_each其实相当于把for() {这儿}花括号里面的东西提炼出来了,有些人习惯,有些人不习惯,不过总体而言,写在for花括号里面的东西相对自由和灵活,而for_each却能强迫你考虑清楚结构和接口。只能说各有利弊吧。
lambda引入到C++以后,我预计for_each会比以前受欢迎。
对于for_each引入一个额外的name,这依赖于是否有利于可理解性,是否有利于重用,但是显然破坏了局部性。
在没有lambda之前,可以用一个unnamed namespace来制造一个“local name”。

Eric.Wang

unread,
May 14, 2009, 9:24:39 PM5/14/09
to TopLanguage
要模块化的话,

for (it = vector.begin; it != vector.end(); it++)
{
obj* p = (*it);
p->detach_from(this);
p->stop();
delete p;
}

就封装成一个函数void delete_all_obj();里面想怎么写怎么写,外面只要写一行代码调用就可以了。


On 5月15日, 上午9时19分, up duan <fixo...@gmail.com> wrote:
> 2009/5/15 Eric.Wang <wangshaoq...@gmail.com>

Eric.Wang

unread,
May 14, 2009, 9:28:08 PM5/14/09
to TopLanguage
Linus就是这么做的。
我其实很长时间也不喜欢用vector,我工作之后用了六年才开始使用vector,实在是被vector熏陶坏了。我还守着底线,那就是vector
只用来存放基础数据类型和pointer。

Eric.Wang

unread,
May 14, 2009, 9:31:20 PM5/14/09
to TopLanguage
提炼有很多种,而boost::for_each的提炼几乎是最差的那种。

去看看C#的for_each是怎么做的吧。那才是优美的for_each()语法。

up duan

unread,
May 14, 2009, 9:35:44 PM5/14/09
to pon...@googlegroups.com


2009/5/15 Eric.Wang <wangsh...@gmail.com>

要模块化的话,
for (it = vector.begin; it != vector.end(); it++)
{
 obj* p = (*it);
 p->detach_from(this);
 p->stop();
 delete p;
}

就封装成一个函数void delete_all_obj();里面想怎么写怎么写,外面只要写一行代码调用就可以了。

我呢,不觉得这样有助于管理复杂性。我倒是宁愿把for的{}里面的事情抽象出来作为一个functor,然后for_each也不会比你调用这个函数复杂吧。这样我觉得才是分解复杂性的办法。而你的那个似乎没有怎么分解。
尤其是for的{}里面确实是很复杂的处理的时候,我宁愿一次面对一个元素考虑清楚而不是跟一个循环纠缠在一起考虑。

Jia

unread,
May 14, 2009, 12:36:32 PM5/14/09
to TopLanguage
首先,这个例子中的 if 判断破坏了函数 draw_all 的语意,这使得 draw_all 不再具有通用性
其次,在有 draw_all 的情况下,这个功能的实现个人觉得应该是

void draw_all_visible(vector<Shape*>& vs, Graphics* graph)
{
vector<Shape*>& vs_v;
remove_copy_if(vs.begin(), vs.end(), back_insert_iterator(vs_v), !
boost::bind(IsVisible(), _1));
draw_all(vs_v.begin(), vs_v.end());
}

尽管效率上要差一些,但这样的写法可读性强和复用性要好一些。


On 5月14日, 下午5时02分, qiaojie <qiao...@gmail.com> wrote:
> 你这例子太过简单
>
> 如果代码是这样的:


> void draw_all(vector<Shape*>& vs, Graphics* graph)
> {
> for (int i=0; i<vs.size(); ++i)
> if(vs[i]->IsVisible())
> vs[i]->draw(graph);
> }

> 又该怎么办呢?
>

up duan

unread,
May 14, 2009, 9:39:41 PM5/14/09
to pon...@googlegroups.com


2009/5/15 up duan <fix...@gmail.com>

另外,我的分解方式似乎可重用性更好一些,比如:如果我需要对一个容器中的某些符合条件的元素进行处理而不是全部,我可以不需要修改这个functor【当然也可以修改】,我只需要写一个filter就可以了【这似乎是典型的fp思路!】,而你的却需要在for的{}里面添加一个判断,并且导致层次更深,缩进更多。

当然,初看起来两者都差不多,都需要修改或者添加某些东西,

Eric.Wang

unread,
May 14, 2009, 9:41:06 PM5/14/09
to TopLanguage
一定要提取?看看我会怎么提取:

void some_class::free_obj(obj* p)
{
if (p == NULL)
return;

p->detach_from(this);
p->stop();
delete p;
}

some_class::~some_class()
{


for (it = vector.begin; it != vector.end(); it++)
{

free_obj(*it);
}
}

以后想在void free_obj()里面做任何修改都很方便。只有free_obj()真的很复杂的时候,我才会这样提取。


On 5月15日, 上午9时35分, up duan <fixo...@gmail.com> wrote:
> 2009/5/15 Eric.Wang <wangshaoq...@gmail.com>
>

up duan

unread,
May 14, 2009, 9:41:42 PM5/14/09
to pon...@googlegroups.com


2009/5/15 Eric.Wang <wangsh...@gmail.com>
Linus就是这么做的。

Linus是谁呀。哈哈。他不用自然有他不用的理由,但不能当做你不用的理由啊。明星崇拜在技术界应该没有市场才对啊。
 

我其实很长时间也不喜欢用vector,我工作之后用了六年才开始使用vector,实在是被vector熏陶坏了。我还守着底线,那就是vector
只用来存放基础数据类型和pointer。

 理由是什么?

Eric.Wang

unread,
May 14, 2009, 9:44:54 PM5/14/09
to TopLanguage
我只是想告诉你,不用vector也很正常。

我知道一家程序员100+的软件公司,专门用C++的。就从不用vector。那家公司有传闻说快上市了,即使是谣传,这家公司起码也是那个行业内的一
流公司。


On 5月15日, 上午9时41分, up duan <fixo...@gmail.com> wrote:
> 2009/5/15 Eric.Wang <wangshaoq...@gmail.com>
>

up duan

unread,
May 14, 2009, 9:45:50 PM5/14/09
to pon...@googlegroups.com


2009/5/15 Eric.Wang <wangsh...@gmail.com>

提炼有很多种,而boost::for_each的提炼几乎是最差的那种。

去看看C#的for_each是怎么做的吧。那才是优美的for_each()语法。

C#的用过。没有感觉有什么太大的差别啊。怎么你对它俩态度差别这么大呢?

up duan

unread,
May 14, 2009, 9:46:55 PM5/14/09
to pon...@googlegroups.com


2009/5/15 Eric.Wang <wangsh...@gmail.com>

一定要提取?看看我会怎么提取:

void some_class::free_obj(obj* p)
{
 if (p == NULL)
   return;

 p->detach_from(this);
 p->stop();
 delete p;
}

some_class::~some_class()
{
 for (it = vector.begin; it != vector.end(); it++)
 {
   free_obj(*it);
 }
}

以后想在void free_obj()里面做任何修改都很方便。只有free_obj()真的很复杂的时候,我才会这样提取。
 
嗯,这样的话,我不知道你的for循环怎么比for_each好了:)

up duan

unread,
May 14, 2009, 9:49:20 PM5/14/09
to pon...@googlegroups.com


2009/5/15 Eric.Wang <wangsh...@gmail.com>
我只是想告诉你,不用vector也很正常。

其实这你倒不用告诉我,因为不光不用vector正常,不用C++也很正常,不用电脑都很正常:)
 

我知道一家程序员100+的软件公司,专门用C++的。就从不用vector。那家公司有传闻说快上市了,即使是谣传,这家公司起码也是那个行业内的一
流公司。

然后,你的意思是?因此不用vector跟一流是密切相关的?如果不是,这样说的意思是什么呢?

Eric.Wang

unread,
May 14, 2009, 9:51:38 PM5/14/09
to TopLanguage
foreach (Task t in taskArray)
{
if (t->Delayed())
{
t->Stop();
}
}

你自己对比一下,和boost::for_each有多少差别。


On 5月15日, 上午9时45分, up duan <fixo...@gmail.com> wrote:
> 2009/5/15 Eric.Wang <wangshaoq...@gmail.com>
>

It is loading more messages.
0 new messages