4.1 右尖括号>的改进

类别:所有人

在C++98中,有一条需要程序员规避的规则:如果在实例化模板的时候出现了连续的两个右尖括号>,那么它们之间需要一个空格来进行分隔,以避免发生编译时的错误。我们可以看代码清单4-1所示的例子。

代码清单4-1


template<int i>class X{};

template<class T>class Y{};

Y<X<1>>x1;//编译成功

Y<X<2>>x2;//编译失败

//编译选项:g++ -c 4-1-1.cpp


在代码清单4-1中,我们定义了两个模板类型X和Y,并且使用模板定义分别声明了以X<1>为参数的Y<X<1>>类型变量x1,以及以X<2>为参数的Y<X<2>>类型变量x2。不过x2的定义编译器却不能正确解析。在x2的定义中,编译器会把>>优先解析为右移符号。使用gcc编译的时候,我们会得到如下错误提示:


4-1-1.cpp:5:9:error:'x2'was not declared in this scope

Y<X<2>>x2;//编译失败

^

4-1-1.cpp:5:9:error:template argument 1 is invalid

4-1-1.cpp:5:3:error:template argument 1 is invalid

Y<X<2>>x2;//编译失败


事实上,除去嵌套的模板标识,在使用形如static_cast、dynamic_cast、reinterpret_cast,或者const_cast表达式进行转换的时候,我们也常会遇到相同的情况。


const vector<int> v=static_cast<vector<int> >(v);//无法通过编译


C++98同样会将>>优先解析为右移。C++11中,这种限制被取消了。事实上,C++11标准要求编译器智能地去判断在哪些情况下>>不是右移符号。使用C++11标准,代码清单4-1所示代码则会成功地通过编译。

不过这些“智能”的判断也会带来一些与C++98的有趣的不兼容性。比如用户只是想让>>在模板的实例化中表示的是真正的右移,但是C++11会把它解析为模板参数界定符。比如代码清单4-2所示的代码。

代码清单4-2


template<int i>class X{};

X<1>>5>x;


如果使用C++98标准进行编译的话,这个例子会编译通过,因为编译器认为X<1>>5>x;中的双尖括号是一个位移操作,那么最终可以得到一个形如X<0>x的模板实例。而如果使用C++11标准进行编译,那么程序员会得到一个编译错误的警告,因为编译器优先将双尖括号中的第一个>与X之后的<进行了配对。

虽然很少有人在模板实例化时同时进行位移操作,但是从语法上来说,C++98和C++11确实在这一点上不兼容。要避免这样的不兼容性也很简单,使用圆括号将“1>>5”括起来,保证右移操作优先,就不会出现类似问题了。