强大的C++——库扩充语言

longshanks 2007-04-28 11:24:37
通常,一种编程语言都会有一套基础的库如影随形。语言本身负责提供运算和处理,而库(基本上)利用语言提供的机制实现一些特定的功能,如IO。但离开了基础库,语言也就顶多做个加减乘除,而且你连结果都看不到。
但是,在C++中,库不再是一个陪衬,不再仅仅提供与系统相关的操作。得益于C++强大灵活的语言机制,库甚至具备了扩展语言机制的能力。这种能力在各类语言中算是凤毛麟角的。在主流的语言中,几乎是独此一家的。(Ada也是足够强大的语言,但我不清楚是否也具备这种能力。若有高手知晓,请明示)。
在此,我举两个例子:一个是“模板表达式”,另一个是Type Traits。
模板表达式,Template Expression,是缓式评估(Lazy Evaluate)技术的一个运用。(关于缓式评估,More Effection C++有详细论述)。先看下面的代码片段:
template<typename T>
vector<T> operator+(const vector<T>& op1, const vector<T>& op2) {

}

template<typename T>
vector<T> operator*(const vector<T>& op1, const vector<T>& op2) {

}

vector<double> prise(1000), quantity1(1000), quantity2(1000), result(1000);
… //初始化v1,v2,v3
result=prise*(quantity1+quantity2);
这里我们已经为vecotr<>定义了+和*,着两个操作将两个vector的对应元素相加和相乘。这段代码似乎是在对两个仓库进行合并盘货。我们先不去管它干什么,来谈谈效率问题。
...全文
407 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
michaeldg 2007-04-30
  • 打赏
  • 举报
回复
谢谢楼主!让我打开眼界!
roger_77 2007-04-30
  • 打赏
  • 举报
回复
mark
学习了
longtramp 2007-04-29
  • 打赏
  • 举报
回复
look
不想低调 2007-04-29
  • 打赏
  • 举报
回复
longshanks 2007-04-29
  • 打赏
  • 举报
回复
补充一点,那么remove_pointer的用法如下:
//有人定义了这个,而你需要用:
typedef int********* IntWithStars; //哪个王八蛋干了这等鸟事!!!

//你可以将其化解于无形:
remove_pointer<IntWithStars>::result i=100;
chenm91 2007-04-28
  • 打赏
  • 举报
回复
mark
taodm 2007-04-28
  • 打赏
  • 举报
回复
说实话,虽然只在钻研C++,也很喜欢C++界的挑战自我,可还是认为扩展语言更好。
更自然,更概念完整。
有高手给的评价是:leaky Abstraction是个非常严重的缺陷。这样的结果就是写出一堆看似“精巧”,其实丑陋的、冗余的、违反概念完整性的、难以理解的代码。
jixingzhong 2007-04-28
  • 打赏
  • 举报
回复
just have a look
lidongri 2007-04-28
  • 打赏
  • 举报
回复
make
freshui 2007-04-28
  • 打赏
  • 举报
回复
makel
longshanks 2007-04-28
  • 打赏
  • 举报
回复
表达式result=prise*(quantity1+quantity2);很正确,但也很糟糕。因为每当调用+或*时,编译器便会产生一个用于装载结果的vector临时对象。即使考虑编译器优化,仅这个表达式本身,就产生至少两个临时对象。如果运算的是int或double,这些临时对象也没什么。但这里是vector,是个类,是有构造函数和析构函数。并且还需要将临时对象的内容来回拷贝。对于数值计算而言,这种性能下降是无法忍受的。(或许Java程序员能够忍受,但是我肯定受不了。)。
为了消除这个问题,我们应该用手工循环代替一个单独的表达式:
for(int i=0; i<prise.size(); ++i) {
result[i]=prize[i]*(quantity1[i]+quantity2[i]);
}
这样够正确,也够快,但不够简洁。要简洁,还是原来的表达式好。模板表达式为我们提供了这样的能力:用数学运算的表达式,但拥有手工循环的性能。
这里只是大概描述一下模板表达式的概念,具体细讲,可以写本书了。详细的内容可以很容易在网上搜到。
模板表达式的基本原理是,通过重载*和+操作符。这些重载不立即计算,而是将操作数存放在一个中间类的对象中,并记录相应的运算操作,然后返回这个对象。下一个运算操作符对中间类进行了重载,将他的操作数存放在这个对象中,记录运算操作,然后也返回这个对象。以此类推。这个过程实际上生成了一个解析树。最后,在=的作用下,中间类对象提取出vector的每一个元素,代入解析树计算,得出最终的结果。这样,所有计算只需一个循环,并且不产生临时对象,也无需反复拷贝。同时,模板的展开机制使得整个表达式在编译时展开,并最终形成类似手工循环的结构。(可惜我们看不到具体的代码,只能想象了)。
除了提高性能外,表达式模板还为我们带来所谓的“higher-ordering programming”(高阶编程)。简单地讲,高阶编程就是将函数作为值使用的能力。C++中最杰出的代表就是Lambda表达式。Lambda是Boost中的一个库,尽管不是标准库,但也很接近了。
下面的代码给出了Lambda的一个典型应用(来源于真实的应用):
string p(…), k(…);
vector<unsigned char> c(p.size());

transform(p.begin(), p.end(), k.begin(), c.begin(), _1^_2);
很简单吧。这段代码将p的每个字符异或k的每个字符,结果存放到c中。如果没有Lambda,我们只能写个for循环,或者写一个函数对象进行操作。
实际上,Lambda表达式通过占位符_1和_2(最多到_3,但可以扩展)和重载后的操作符相互作用,最终生成一个包含对应此表达式解析树的函数对象,传入transform算法。
其它的应用还很多,比如我要删除一个字符串中的’-‘和’/’,那么可以这样写:
remove_if(s.begin(), s.end(), _1==’-’|| _2==’/’)
再多也没问题。很神奇吧。
小结一下,C++语言本身没有缓式计算和Lambda的功能。但由于C++强大灵活的功能,使得我们可以通过库实现这些语言特性。而这些特性通常在其它语言中,只有扩展语言才能办到。
Type Traits主要用来描述一个类型的特性,比如一个类型是否是内置类型(int,long等),是否是指针,是否是类,是否是函数等等。这些功能通常必须由语言提供,但C++根本不提供这类东西,反而是库实现了它们。Boost中专门有一个Type traits库,提供了几十个分析类型特性的模板(也叫meta-function)。
这里不打算对特性分析作演示,它们太“平常”了。这里有个很酷的:去除指针类型的指针。也就是:要去掉int***的***,得到int。实现的代码很简单:
template<typename T>
struct remove_pointer
{
typedef T result;
};

template<typename T>
struct remove_pointer<T*>
{
typedef typename remove_pointer<T>::result result;
};
这里使用了模板局部特化和递归。两者相结合,一层一层地剥去T上的*。
好了,对于库扩展语言这个话题就到这里。其它好玩的东西,以后再讲。
AiNiLife 2007-04-28
  • 打赏
  • 举报
回复
mark
dl_27 2007-04-28
  • 打赏
  • 举报
回复
mark 虽然看的不太懂,也要顶一个
lisen07 2007-04-28
  • 打赏
  • 举报
回复
mark
nevergone 2007-04-28
  • 打赏
  • 举报
回复
mark

顶taodm的话

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧