在boost 中大量使用了模板这一"静态类生成器", 一个模板的参数化,在编译器看来好似是有一个类被声明了, boost中的模板在编译期间生成
了大量对于库用户不知道的类,即"中间类"(不知道这样描述是否合适?),而这些"中间类" 和静态设施一起在编译期使编译器帮我们 计算(很多是利用
模板的静态递归特性)了很多静态内容。其实这些都是复杂因素, 这些都对编译器提出了要求:静态计算也是要耗时的,耗的是编译时间, 长时间的编译对开
发者不是好的体验。
然而, 对一般应用而言用户要求得更多的可能是运行时的计算能力, 而boost库过多的使用模板---这一编译期的计算工具是否有点偏颇?
在一些著名的开源C++工程项目中我们也很少看到boost的身影, boost的实用价值到底有多大, 她的设计理念对C++语言而言是否是有益的?
2009/5/13 jiang yudong <nebul...@gmail.com>:
2009/5/13 jiang yudong <nebul...@gmail.com>:
至于编译时间很长这个问题我也发现了,我的解决方法是把它包装一下,大致这样:
$ 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的时候不会重新编译。
我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。
2009/5/13 stlf <stlflin...@gmail.com>:
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>:
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>:
2009/5/13 missdeer <miss...@gmail.com>:
我觉得boost是在把简单问题复杂化,像shared_ptr, bind, function, lambda,
foreach这些东西纯粹是语法糖,本来就是些很简单很基础的东西,应该用KISS的方法处理他们,可boost却用一个巨大的库去实现他们,这个理念我完全不认同。又因为boost本身是C++专家们开发的,由于其权威性所以更加具有误导性。
我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。
另外boost的众多库基本很难构成一个完整的架构体系,这也是其很难成为日常开发的基础类
库的原因。其实boost虽然有工业强度,但其本身承载的更多的还是实验性质。
说到底,c++程序员最需要的是一个系统化,简洁高效, 并且实用的的标准库。
2009/5/14 up duan <fix...@gmail.com>:
boost是在试图使用户编程简单化, 她提供了一系列的portable工具给我们使用, 其中确实不
乏精巧实用的工具, 但有些库可能就有语法糖之嫌。我觉得她提供的工具确实很高级但有些是
不是一般用户最需要的 这一点是值得商榷的。
另外boost的众多库基本很难构成一个完整的架构体系,这也是其很难成为日常开发的基础类
库的原因。其实boost虽然有工业强度,但其本身承载的更多的还是实验性质。
说到底,c++程序员最需要的是一个系统化,简洁高效, 并且实用的的标准库。
既然shared_ptr,bind,function,lambda这些东西用C++实现起来很困难代价很大,那为什么一定要支持呢?我不认为这些语法糖可以提高软件生产效率。没有他们C++代码一样可以写,日子还是照样过,但是却减轻了程序员的很多脑力负担,不要忘记,程序的设计才是我们需要解决的主要矛盾,沉迷于这些杂七杂八的语法糖只会分散对主要问题的注意力,这程序还能设计的好么?想想Linus为什么要批判C++?C语言里的语法糖少的可怜,不是一样开发出了很多伟大的软件?
如果这些特性对程序设计的是重要的,那么应该由语言特性本身去支持,你不是也意识到是语言自身的限制造成的问题么?我们完全可以放弃C++,改用其他更高级的语言来完成。
>>
>> 我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。
>>
>
> 我也很欣赏ATL,而且我认为它是诡异的递归模板参数使用方式的第一库,这也几乎构成了《现代C++设计》一书的主要技术支撑点。但是你说的编译不慢这个问题其实是误解。没有理由都是大量的使用模板一个库编译的慢而另一个编译的快。
ATL编译不慢是因为代码量少,几千行的核心代码,放到预编译头文件里就完成编译了。而boost随便引入一个头文件就几千行了,又不可能都放到预编译头里去,编译速度自然就很慢了。
2009/5/14 OxFAN <oday...@gmail.com>:
> 2009/5/13 qiaojie <qia...@gmail.com>既然shared_ptr,bind,function,lambda这些东西用C++实现起来很困难代价很大,那为什么一定要支持呢?我不认为这些语法糖可以提高软件生产效率。没有他们C++代码一样可以写,日子还是照样过,但是却减轻了程序员的很多脑力负担,不要忘记,程序的设计才是我们需要解决的主要矛盾,沉迷于这些杂七杂八的语法糖只会分散对主要问题的注意力,这程序还能设计的好么?想想Linus为什么要批判C++?C语言里的语法糖少的可怜,不是一样开发出了很多伟大的软件?
>>
>> 我觉得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编译不慢是因为代码量少,几千行的核心代码,放到预编译头文件里就完成编译了。而boost随便引入一个头文件就几千行了,又不可能都放到预编译头里去,编译速度自然就很慢了。
>>
>> 我个人最欣赏的C++库是ATL,首先他来自于实际工程项目的需求,着眼于解决实际问题,极大的简化了COM的开发,而不是一堆华而不实的东西。其次是代码够轻量,ATL的核心代码也就几千行,花上个把月就可以熟读,编译出来的代码也很小巧,也不存在编译慢的问题。最后是代码也够精妙,很好的发挥出了C++模板的优点,写出来的COM代码比较优雅,没有给人繁琐难用的不良感觉。
>>
>
> 我也很欣赏ATL,而且我认为它是诡异的递归模板参数使用方式的第一库,这也几乎构成了《现代C++设计》一书的主要技术支撑点。但是你说的编译不慢这个问题其实是误解。没有理由都是大量的使用模板一个库编译的慢而另一个编译的快。
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++的比较都是没有意义的,因为基本没有公平的比较。- 隐藏被引用文字 -
>
> - 显示引用的文字 -
boost跟STL一样是个基础库,很多基础组件都是为了通用程序而写的,所以如果要用的话,肯定是适合几乎所有C++程序的,不存在你说的需求问题,所以不要偷换概念,大谈什么适用性的问题。boost花了那么大力气,动用了各种奇巧淫技去模拟那些高级语言的特性,典型的高射炮打蚊子,我不知道这能提高多少软件生产力,但是由此带来的问题是显而易见的,这不是个人喜好问题,而是一个事实。
Sincerely, Ian Yang
Sent from Shanghai, 31, China
觉得C++的库难流行有个很重要的原因是:用C++的开发者似乎对第三方库都很不信任,更情愿自己写一个。
Sincerely, Ian Yang
Sent from Shanghai, 31, China
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#去写了,更用不上了。这玩意的使用也不是免费的,对象的生命周期不太好管理,会带来
额外的复杂性。
我没有全面批判C++,事实上我仍然会有一半的工作基于C++来开发,我只是针对某些库滥用C++的情况做一些批判,
C++很灵活用法很多,用好用坏千差万别,这个在其他语言里是非常少见的,所以有争议也是非常正常的。
另外,对 .net的底层实现机制我也很有兴趣啊,用C++/CLI的话会比较注重这方面。
> 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++函数对象-,会有种想吐的感觉。
for_each我从来不用,C++没有lambda,写出来的for_each代码是很丑陋的,宁可用for的。函数对象最大的问题是不能定义在函数里面,导致本来一段高内聚的代码变得东一块西一块,函数对象里虽然可以带状态,但是这些状态要共享起来又非常麻烦。用惯脚本语言的lambda以后,再看C++函数对象,会有种想吐的感觉。
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);
}
然而我们又确实很想说明“first和last必须为前向迭代器”:
template<Forward_iterator<Shape*> Iter>
void draw_all(Iter fist, Iter last)
{
for_each(first, last, mem_fun(&Shape::draw);
}
这是“concepts”可以大展拳脚的地方之一。
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我在实际工作中确实用的不多,但是我在想哪天要用到成员函数指针的时候, 除了上面第一种写法之外,怎么写才能更加直
观
拿来主义也是我一贯奉行的标准,当然这事得看具体情况,为了一个smart pointer而引入boost库我觉得代价太大了点,
其实Loki::SmartPointer我也用过,不过不符合我的使用习惯和设计理念:-) 所以就干掉,自己实现了一个。不过,不要
就此认为我的习惯就是凡事都喜欢自己实现。
如果代码是这样的:
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:
> 如果你面对的问题既需要某些运行期决议(需要面向对象编程),又具有一些能够从编译期决议中获益的方面(泛型编程的用武之地)的话,那么你就需要将面向对象编程和泛型编程结合起来。例如,面向对象编程的经典例子
> --
我只想知道这个例子你用for_each怎么写?
难道这个例子很过分,很特殊吗?
2009/5/14 up duan <fix...@gmail.com>:
2009/5/14 LeeoNix <leeo...@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);
}
那是不是boost里还有一个for_each_if_else啊?
是不是还要发明一个for_each_switch 啊?
2009/5/14 LeeoNix <leeo...@gmail.com>:
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>
或者用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>:
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 啊?
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>:
把代码写成这样,首先就毫无可读性了。但最重要的一点是,每次你写
迭代的时候就会分神去考虑用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>:
好了,回过头来跟for代码比较一下吧,你们所标榜的
boost的简洁优雅,可读性,性能在哪里体现出来了?
2009/5/14 Ian Yang <doit...@gmail.com>:
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>:
Sincerely, Ian Yang
Sent from Shanghai, 31, China
2009/5/14 hyifeng <hyi...@gmail.com>:
那么你现在告诉我,这里用for_each到底有什么好处?
2009/5/14 up duan <fix...@gmail.com>:
2009/5/14 LeeoNix <leeo...@gmail.com>:
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},就不在需要这么多辅助设施搞定了。- 隐藏被引用文字 -
>
> - 显示引用的文字 -
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就可以把参数传进去了呀。
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>:
我不知道你这话是指什么?
对于这段代码
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去做比较。
看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用boost::lambda的话,你的项目一定会出问题。
我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。
我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误的C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少人会愿意提及boost了。
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各个库的接口还是非常简洁,并且容易扩充。很多库--只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。
> >> - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -
这里的性能问题非常的复杂,因为会产生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的实现,并且非常了解
编译器的优化机制。这也是从另一方面,由引入高级语法糖带来的思考负担。如果
是关键性能代码段的话,绝对不能这么写。
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各个库的接口还是非常简洁,并且容易扩充。很多库--只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。
> >> - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -
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的认识和一些使用经验而已。
2009/5/14 Ian Yang <doit...@gmail.com>:
>>
>> Sincerely, Ian Yang
>>
>> Sent from Shanghai, 31, China
>
我没有全面批判C++,事实上我仍然会有一半的工作基于C++来开发,我只是针对某些库滥用C++的情况做一些批判,> 照我的看法,这只是一个结果,而不是一个原因。
> 为什么Javaer对Java库能够信任C#er对.NET库能够信任,而C++er对C++库不能信任?因为他们可挑选的太多了,他们能看透实现的太多了,所以他们会觉得自己也可以而且完全应该自己实现一个。
> 当然,他们之所以能看透,能挑选,也是因为大多数C++库大多数都是一个小小的抽象也实现,都没有到达Java库和.net库那种庞大和平台级别。这种现象的一个原因我前面说过:C++不是一个平台,只是一个语言。另一个原因就是历史,那时候人们总是提供细粒度的组件以供重用,跟现在的趋势不同,现在是倾向于提供越来越大的组件。这个趋势跟人们对计算机的期望值越来越高有密切的关系,现在的计算机承载着人类生产力【本来想说人类文明的,觉得太大了点:)】的很大的一部分,要执行越来越庞大越来越复杂的任务,所以,基础组件个头大一点才好掌控,才好控制复杂度。
> 基于这些理由,C++程序员倾向于自己实现库,就算自己不实现,也倾向于看透别人库的实现。比如:qiaojie就用看透C++库如此费神儿批判C++,我觉得他可能从来没有试图去看透过.net库的实现:)。
C++很灵活用法很多,用好用坏千差万别,这个在其他语言里是非常少见的,所以有争议也是非常正常的。
另外,对 .net的底层实现机制我也很有兴趣啊,用C++/CLI的话会比较注重这方面。
boost跟STL一样是个基础库,很多基础组件都是为了通用程序而写的,所以如果要用的话,肯定是适合几乎所有C++程序的,不存在你说的需求问题,所以不要偷换概念,大谈什么适用性的问题。boost花了那么大力气,动用了各种奇巧淫技去模拟那些高级语言的特性,典型的高射炮打蚊子,我不知道这能提高多少软件生产力,但是由此带来的问题是显而易见的,这不是个人喜好问题,而是一个事实。
2009/5/14 OxFAN <oday...@gmail.com>:
> 很多人都在说这个库哪里哪里不行,说那个库哪里哪里不行,但没见人给出一个“可行”的方案的。
> 更何况,这些被提出来的“缺点”,没有任何有力的证据证明他们真的是设计缺陷。
> 如果你使用一个库之前连自己的需求和这个库是否适合你的需求都不清楚,那么在此基础上的任何评价都是没有意义的。如果它适合,那么就用它,如果不适合,那就不要用,并且第二种情况很正常也很普遍,然后你只要去寻找更合适的就行了,而不应该在公共场合披露这个库所谓的“缺点”。
> 任何语言、库、系统都有它适用的地方,没有什么是完美的,不可能满足每个人的爱好,单纯的根据个人喜好来评判这个那个,说白了是浪费所有人的时间。
>
> 还有,看到前面有人又把别的语言扔出来了,就像c++之父说的那样,任何将其他语言与c++的比较都是没有意义的,因为基本没有公平的比较。
因为最重要、最实用的基本算法和容器已经被包含在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>:
>
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各个库的接口还是非常简洁,并且容易扩充。很多库--只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。
> >> - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -
上次看到有人说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各个库的接口还是非常简洁,并且容易扩充。很多库--只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。
> > >> - 显示引用的文字 -- 隐藏被引用文字 -
>
> - 显示引用的文字 -
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多
做一点事情怎么办?写的人爽了,维护的人惨了。
用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>:
好吧,这样不扭曲,至少我还能看的懂
不过论简洁性:你这个for_each用了8行代码,而for只要5行
论可读性:显然for更容易理解
论性能:debug版下for_each肯定差,release可能可以打个平手。
那么你现在告诉我,这里用for_each到底有什么好处?
for_each既然不适合处理复杂的事务,那么还抽象什么,搞什么中间层?for_each就是一颗难吃的语法糖。
On 5月15日, 上午9时00分, up duan <fixo...@gmail.com> wrote:
> 2009/5/14 qiaojie <qiao...@gmail.com>
>
看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用boost::lambda的话,你的项目一定会出问题。
我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。
我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误的C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少人会愿意提及boost了。
> 最后说性能,要比性能debug肯定不能纳入考虑的范围,而release,你也只是说"可能",说实话我也没真实测过,不过一直以来那些教科书上都说这里的性能问题非常的复杂,因为会产生2个临时对象,要看编译器是怎么实现的。
> for_each如果搭配functor可以在线展开从而省掉一个函数调用的开销,我所知道的仅止于此。
如果写成
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的实现,并且非常了解
编译器的优化机制。这也是从另一方面,由引入高级语法糖带来的思考负担。如果
是关键性能代码段的话,绝对不能这么写。
> > > 看来被boost毒害的不轻。我不知道你做什么领域的开发,这么迫切的需要在C++里使用lambda。但是我可以负责任的告诉你,如果你在项目中大量的用bo--ost::lambda的话,你的项目一定会出问题。
>
> > > 我想这里很多人在跟我辩论,只是为了争个口舌之快,为了辩论已经丧失了基本的价值观判断,丧失了理性的判断,我已经不想再辩论下去了,要争个输赢没什么意思。
>
> > > 我只想说,C++这些年的发展根本就是每况愈下,越来越多的理性的程序员开始厌恶C++,有的回到了C阵营,有的转向了脚本语言,还有的投奔了java和C#阵--营。为什么呢?我觉得这是C++社区自身的价值观出现了问题。大家都认为C++缺乏好的库支持,可是boost却带了一个不好的坏头,他集中的体现了这种错误-的-C++价值观,boost是走在一条错误的道路上,注定了它对开发社区的影响力会越来越小,今天我说这话可能为时尚早,但是5年以后,我敢打赌不会再有多少-人会-愿意提及boost了。
> > > >> >>> 作为基础库,boost很多库都做得很全,另一方面也是很臃肿,不过考虑到通用性,也无可厚非。其实Boost各个库的接口还是非常简洁,并且容易扩充。很多库---只需要几分钟,就能使用核心的功能了,而这些核心功能能满足大部份的需求。
对于那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();
这样不是更清爽吗?以后修改起来也方便。
你这里for_each有个矛盾:
1、"处理繁复的话,影响可理解性"
2、"提供了一个间接层和一个抽象的机会"
for_each既然不适合处理复杂的事务,那么还抽象什么,搞什么中间层?for_each就是一颗难吃的语法糖。
就封装成一个函数void delete_all_obj();里面想怎么写怎么写,外面只要写一行代码调用就可以了。
On 5月15日, 上午9时19分, up duan <fixo...@gmail.com> wrote:
> 2009/5/15 Eric.Wang <wangshaoq...@gmail.com>
去看看C#的for_each是怎么做的吧。那才是优美的for_each()语法。
要模块化的话,
for (it = vector.begin; it != vector.end(); it++)就封装成一个函数void delete_all_obj();里面想怎么写怎么写,外面只要写一行代码调用就可以了。
{
obj* p = (*it);
p->detach_from(this);
p->stop();
delete p;
}
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);
> }
> 又该怎么办呢?
>
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>
>
Linus就是这么做的。
我其实很长时间也不喜欢用vector,我工作之后用了六年才开始使用vector,实在是被vector熏陶坏了。我还守着底线,那就是vector
只用来存放基础数据类型和pointer。
我知道一家程序员100+的软件公司,专门用C++的。就从不用vector。那家公司有传闻说快上市了,即使是谣传,这家公司起码也是那个行业内的一
流公司。
On 5月15日, 上午9时41分, up duan <fixo...@gmail.com> wrote:
> 2009/5/15 Eric.Wang <wangshaoq...@gmail.com>
>
提炼有很多种,而boost::for_each的提炼几乎是最差的那种。
去看看C#的for_each是怎么做的吧。那才是优美的for_each()语法。
一定要提取?看看我会怎么提取:
void some_class::free_obj(obj* p)
{
if (p == NULL)
return;
some_class::~some_class()
p->detach_from(this);
p->stop();
delete p;
}
{free_obj(*it);
for (it = vector.begin; it != vector.end(); it++)
{
}
}
以后想在void free_obj()里面做任何修改都很方便。只有free_obj()真的很复杂的时候,我才会这样提取。
我只是想告诉你,不用vector也很正常。
我知道一家程序员100+的软件公司,专门用C++的。就从不用vector。那家公司有传闻说快上市了,即使是谣传,这家公司起码也是那个行业内的一
流公司。
你自己对比一下,和boost::for_each有多少差别。
On 5月15日, 上午9时45分, up duan <fixo...@gmail.com> wrote:
> 2009/5/15 Eric.Wang <wangshaoq...@gmail.com>
>