Profil de 页希I am who I amPhotosBlogListesPlus ![]() | Aide |
|
7 septembre 用C++新编译器遇到的问题 直到最近我都还一直用的VC++6.0,这两天觉得新学期应该有新气象,决定安装个VS2005来适应新时代。折腾了一天后(下载,清理硬盘空间-_-b,安装),一个崭新的界面终于呈现在我眼前。恩,看起来是不错,界面感觉比6.0的现代化多了。 随即打开以前写的一个工程看看运行效果,谁知弹出一堆编译错误。不对啊,以前这个程序明明是调试通过了的,怎么可能...不会是RPWT吧.TT。没办法,一个个改吧... 看了看第一个错误是“warning C4346: 'BinSearchTree<T>::tree_node' : dependent name is not a type”。报错的地方是在27行,而我之前定义了个tree_node结构。 19 struct tree_node 20 { 21 T item; 22 tree_node *parent, *left, *right; 23 bool isHeader; 24 tree_node(){} 25 //tree_node(Iterator it){} 26 }; 27 typedef BinSearchTree<T>::tree_node* Link; 这里看起来没有任何错误 ,而且 错误确实只是针对这一行的,没有涉及后面的地方。这个错误也是我以前没有碰到过的,至少6.0没有报过这种错误。于是在网上查了一下。这一查也增长了见 识,原来这一句话是有歧义的。因为对于编译器来说,它并不知道什么是BinSearchTree<T>::tree_node,事实上 tree_node是一个嵌套依赖名字(nested dependent name),更准确的说是一个涉及到type类型的 嵌套依赖名字。也许现在说得还不是很明白,但看了下面一个例子就会知道了。 假设我们这样定义两个类: class Dummy { public: static int subOne; struct subIterator { T item; ……blablabla…… }; }; //另一个文件 template<class C> class Another { public: C& container; ……blablabla…… void visitDummy(const C& co); }; void Another<C>::visitDummy(const C& co) { C::subIterator *c; ……blablabla…… } 第一个类里面有两个成员,一个静态成员变量subOne,一个嵌套的结构体subIterator,其中包含一个成员变量。如果这时我们要在 visitDummy方法中得到subIterator,我们可能会采取上面看到的方法"C::subIterator *c;",咋一看,合情合理,在VC++6.0里面确实也没有问题,然而在2005里面这个会被看成是模棱两可的代码。这是为什么呢?因为我们编程的时候 总是按照自己的思路去思考,而不是按照编译器的方式去解释代码。对于人来说,这句话显而易见的变量申明。但是对编译器来说,它要考虑的问题就不仅仅是这点 代码了,它必须考虑到所有的情况。 而一种可能的情况就是,如果subIterator是一个静态数据成员,而恰巧c是一个全局变量,那么这行代码就表示的是乘法运算!这样,在单个文件中, 编译器就没法排除这样的可能性,它不知道C类型的具体情况,也就是说编译器不能区分这个是一个变量申明还是一个单纯的乘法问题!这看起来是一个愚蠢的问 题,但是编译器必须要考虑到所有的情况,哪怕是荒谬的,这就是它的严密性(可见2005的编译器比6.0严密)。 现在问题是发现了,怎么解决呢?当然是消除这种模棱两可的状况,我们要明确的告诉编译器这是一个类型而不是一个变量,这里我们就要把typename这个关键词紧挨着放在类型前面。 void Another<C>::visitDummy(const C& co) { typename C::subIterator *c; ……blablabla…… } 这样问题就消除了。同理,在返回值,typedef定义时也需要这个关键词。比如在我的代码中: 27 typedef typename BinSearchTree<T>::tree_node* Link; 522 typename BinSearchTree<T>::Iterator BinSearchTree<T>::Iterator::operator--() 523 { 524 ……blablabla…… 525 } 当然,这个规则也有例外。那就是typename不必前置于一个基类列表(list of base classes)中或者在一个成员初始化列表(member initialization)中作为一个基类标识符(base classes identifier)的嵌套依赖类型名(nested dependent type name)。比如 : tamplate<typename T> class Derived: public Base<T>::Nested //基类列表不需要typename { public: explicit Derived(int x) :Base<T>::Nested(x) //成员初始化列表不需要typename { typename Base<T>::Nested temp; //变量申明需要typename ……blablabla…… } }; 一些编译器接受必需 typename 时它却缺失的代码;一些编译器接受不许 typename 时它却存在的代码;还有少数的(通常是老旧的)会拒绝 typename 出现在它必需出现的地方。这就意味着 typename 和 nested dependent type names(嵌套依赖类型名)的交互作用会导致一些轻微的可移植性问题。 解决了第一个问题后,后面的相关问题也就自动消失了。 参考网页: http://blog.csdn.net/fatalerror99/archive/2005/12/04/543630.aspx 5 septembre 开学前总结整个暑假由于眼睛做手术很多计划都搁浅了,荒废了不少时间。由于不能多用眼睛,电脑不能多用,书也不能多看,加之没怎么锻炼,感觉整个暑假过得很无 聊。从去年十月份决定保研到今年九月这一段时间,除了中途两个月做毕业设计基本上就是在低效率中度过.想想前年这个时间段曾经用17天背了7遍GRE单词 真是有天壤之别. 看来对我来说,只有心中有明确的目标,才能够勤奋起来,否则就像现在一天到晚懒洋洋的,或者努力的程度很低.从大一大二的对未来的一无所知,到大三确 定目标的奋起,不过可惜的是,大学期间仅靠1年的努力是有限的,因此我的梦想还是搁浅了,为求稳妥继续留在了这里.目标的搁浅是很痛苦的,我又进入了漫长 的低效率时期. 眼看新学期开始了,各个学校都已开学,昔日的同学都开始了新的生活,曾经一起奋斗的朋友们不少已经踏上大洋彼岸,开始了新的奋斗.虽然很累,很苦,但 很满足.就连老爸也要到北卡和杜克做访问学者,一圆他青年时代的梦想(拿到的明尼苏达大学的offer,但当时单位不放人).好一个奋斗与圆梦的时代. 今天上网碰到到去港科的同学在群里,一来就问我一个公式的问题(差距啊,别人都在勤奋了我还在虚度).乍一看和物理有关,再一查是和fermat's principle有关,觉得比较棘手(我对物理兴趣不大),只好叫他把ppt传过来看完整的,看后觉得其实后面的公式变化是纯数学问题,这下觉得有点把 握了,但是变来变去总得不到末尾的等式.过了大概20分钟,终于灵光闪现,发现这不过是一个先通过一个三角变换后由泰勒公式展开.我晕,这样一个东西居然 想了这么久,看来数学是废掉了.最后我们得出一致结论,去补补数学吧,免得读研究生时丢人现眼. 还有几天就开学了,下半年的事情还不少,论文修改,青年创新工程,口语学习,貌似还有十一五项目,当然个人提升是少不了的.感觉每天的时间都会被榨干,还好,我喜欢充实的生活.为了不被其他人远远的抛在后面,该好好准备准备,重新瞄准目标,蓄势待发了. |
|
|