昨天同事写一程序,里面一行std::map<int,std::map<int,std::string>> oFuzzyMap;报错,而改成std::map<int,std::map<int,std::string> > oFuzzyMap;让他很迷惑。为什么一定要在右边的">"中间加空格才行呢。
其实,且不说《C++ primer》里面有提到这点,其实从编译的角度来说,是必然会引发问题,导致编译不通过的。
因为编译时,词法分析的时候,会遵从贪心法则,就是扫描器尽量往前扫描,直到遇到一个不能和前面字符组成词为止。也就是说,">>"可以当成一个词(右移操作符),就不会将">>"当成两个词。
而词法分析时">>"被当成一个右移操作符,在语法分析阶段,就会找不到与前面的"<"号相匹配的词,从而引发编译错误。
同事问,那为什么在词法分析时"<>"不能被配对成一个词呢?其实且不说词法分析是顺序扫描,中间有其他字符,会将这两个隔成两个词。"<"与">"跟其他括号一样,必须是两个词法单元,才能在语法分析时被配对。而且,"<"与">"在语法分析时,还具有不同的优先级关系。是不能被配对成一个词法单元的。
又想起去年看到过的一个C++程序:
这个程序编译后运行,结果是什么呢?
初看时会让人纠结,编译运行后,得到结果:
可是这又为什么呢?为什么那不是一句变量的声明语句呢?其实再从编译的角度想想,也是必然的。
在语义扫描时,进入一个程序块,就会产生一个对应的符号表,在编译器语义分析到main函数里面时,其符号表链是这样子的:
若在main函数中有语句块,又会再生成一个符号表,挂到链上去。
在分析vector<UINT4> foo;这句时,编译器以从里向外的顺序在符号表链中找各个标识符的语义信息,找到之后就开始找下一个标识符,因此,stl里面的vector就被shadow了,编译器只会认为它是一个变量。同理,UINT4也是被覆盖了。所以,那语句就被解释成operator > ( operator<(vector, UINT4), foo );
所以,像以下程序中,类型的声明是会被覆盖的,
结果为:
以前看编程的书,总说什么变量名覆盖,严谨来说,其实是标识符覆盖。
如果是团队合作写代码,一定要遵循命名规范,以免因为这种标识符覆盖,写出执行起来让人莫名其妙的程序。
当初学C++,就记住了《C++ primer》里面提到的当模板两个右尖括号在一起时,中间要加空格。就记住了,也没深究。后来痴迷过编译器,倒是没想到能够用学到的编译原理来解释这些问题。昨天被些个问题一带,自已倒是豁然开朗。