Published by orzz.org(). (http://orzz.org/template-specializations-in-cxx11/)
在C++98/03的泛型编程中,模板实例化有个很恼人的地方。那就是连续的两个右尖括号(>>)会被编译器解释成右移操作符,而不是模板参数表的结束。
让我们来看看下面这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
template <typename T> struct Foo { typedef T type; }; template <typename T> class A { // ... }; int main(void) { Foo<A<int>>::type xx; // 编译出错 return 0; } |
使用gcc编译时,我们会得到如下错误提示:
1 2 3 |
error: '>>' should be '>>' within a nested template argument list Foo<A<int>>::type xx; ^ |
意思就是,“Foo>”这种写法是不被支持的,让我们写成这样:“Foo>”(注意两个右尖括号之间的空格)。
这种限制无疑是很没有必要的。在C++的各种成对括号中,目前只有右尖括号连续写两个会出现这种二义性。让我们想象一下,static_cast、reinterpret_cast等C++标准转换运算符,可也都是使用“<>
”来获得待转换类型(type-id)的。若这个type-id本身是一个模板,用起来多么的不方便!
现在在C++11中,这种限制终于被取消了。
参考《ISO/IEC 14882:2011》,14.2 Names of template specializations,第3款:
“When parsing a template-argument-list , the first non-nested > is taken as the ending delimiter rather than a greater-than operator. Similarly, the first non-nested >> is treated as two consecutive but distinct > tokens, the first of which is taken as the end of the template-argument-list and completes the template-id.”
C++11标准中,要求编译器对模板的右尖括号做单独处理,使编译器能够正确判断出“>>”是一个右移操作符还是模板参数表的结束标记(界定符)。
不过这种自动化的处理在某些时候会与老标准不兼容,比如下面这个例子:
1 2 3 4 5 6 7 8 9 10 11 |
template <int N> struct Foo { // ... }; int main(void) { Foo<100 >> 2> xx; return 0; } |
C++98/03的编译器编译是ok的,但C++11的编译器会告诉你:
1 2 3 |
error: expected unqualified-id before '>' token Foo<100 >> 2> xx; ^ |
解决的方法是这样写:
1 |
Foo<(100 >> 2)> xx; // 注意括号 |
这种加括号的写法其实也是一个良好的编程习惯,让我们在书写时倾向于写出无二义性的代码。
在C++11之前,各种C++98/03编译器除了支持标准(ISO/IEC 14882:2003及其之前的标准)之外,还自行做了不少的拓展。
这些拓展中的一部分,后来经过了C++委员会的斟酌和完善,进入了C++11。所以有部分C++11的新特征,在一些C++98/03的老编译器下也是可以支持的,只是由于没有标准化,无法保证各种平台/编译器下的兼容性。
比如像Microsoft Visual C++ 2005,虽然不支持C++11,但在对模板右尖括号的处理上和现在的C++11是一致的。
Published by orzz.org(). (http://orzz.org/template-specializations-in-cxx11/)