1.2 模板的细节改进
C++11改进了编译器的解析规则,尽可能地将多个右尖括号(>)解析成模板参数结束符,方便我们编写模板相关的代码。
1.2.1 模板的右尖括号
在C++98/03的泛型编程中,模板实例化有一个很烦琐的地方,那就是连续两个右尖括号(>>)会被编译器解释成右移操作符,而不是模板参数表的结束。
看一下代码清单1-6所讲的例子。
代码清单1-6 C++98/03中不支持连续两个右尖括号的示例
template <typename T> struct Foo { typedef T type; }; template <typename T> class A { // ... }; int main(void) { Foo<A<int>>::type xx; // 编译出错 return 0; }
使用gcc编译时,会得到如下错误提示:
error: '>>' should be '>>' within a nested template argument list
Foo<A<int>>::type xx;
意思就是,“Foo<A<int>>”这种写法是不被支持的,要写成这样:“Foo<A<int> >”(注意两个右尖括号之间的空格)。
这种限制无疑是很没有必要的。在C++的各种成对括号中,目前只有右尖括号连续写两个会出现这种二义性。static_cast、reinterpret_cast等C++标准转换运算符,都是使用“<>”来获得待转换类型(type-id)的。若这个type-id本身是一个模板,用起来会很不方便。
现在在C++11中,这种限制终于被取消了。在C++11标准中,要求编译器对模板的右尖括号做单独处理,使编译器能够正确判断出“>>”是一个右移操作符还是模板参数表的结束标记(delimiter,界定符)。
不过这种自动化的处理在某些时候会与老标准不兼容,比如下面这个例子:
template <int N> struct Foo { // ... }; int main(void) { Foo<100 >> 2> xx; return 0; } 在C++98/03的编译器中编译是没问题的,但C++11的编译器会显示: error: expected unqualif?ied-id before '>' token Foo<100 >> 2> xx; 解决的方法是这样写: Foo<(100 >> 2)> xx; // 注意括号
这种加括号的写法其实也是一个良好的编程习惯,使得在书写时倾向于写出无二义性的代码。
各种C++98/03编译器除了支持标准(ISO/IEC 14882:2003及其之前的标准)之外,还自行做了不少的拓展。这些拓展中的一部分,后来经过了C++委员会的斟酌和完善,进入了C++11。所以有一部分C++11的新特征,在一些C++98/03的老编译器下也是可以支持的,只是由于没有标准化,无法保证各种平台/编译器下的兼容性。比如像Microsoft Visual C++ 2005这种不支持C++11的编译器,在对模板右尖括号的处理上和现在的C++11是一致的。