这是我在各种编译器中观察到的内容。似乎存在编译器错误。
template <int I>
struct X
{ };
int main(void)
{
X<(16 > 1)> a; // Works on vc9, works on g++ 4.1.2, works on Comeau 4.3.10.1
X<(int(16) > 1)> b; // Works on vc9, works on g++ 4.1.2, works on Comeau 4.3.10.1
X<(16 >> 1)> c; // Works on vc9, works on g++ 4.1.2, works on Comeau 4.3.10.1
X<(int(16) >> 1)> d; // Fails on vc9, works on g++ 4.1.2, works on Comeau 4.3.10.1
X<16 > 1> e; // Fails on vc9, works on g++ 4.1.2, fails on Comeau 4.3.10.1
X<int(16) > 1> f; // Fails on vc9, fails on g++ 4.1.2, fails on Comeau 4.3.10.1
X<16 >> 1> g; // Fails on vc9, works on g++ 4.1.2, fails on Comeau 4.3.10.1
X<int(16) >> 1> h; // Fails on vc9, works on g++ 4.1.2, fails on Comeau 4.3.10.1
}
为什么会出现这种不一致?标准允许/禁止的是什么?在vc9上使用BOOST_AUTO时,此类行为也会导致语法错误。在我看来,Comeau通过拒绝所有没有括号的表达式来做正确的工作。
答案 0 :(得分:8)
C ++ 03的规则如下:
在名称查找(3.4)发现名称是模板名称后,如果此名称后跟
<
,则<
始终被视为模板参数的开头 - 列表,从不作为名称后跟小于运算符。解析模板ID时,第一个非嵌套>
[脚注:A>
包含dynamic_cast
的类型ID,static_cast
,{{ 1}}或reinterpret_cast
,或者包含后续模板ID的模板参数,被认为是嵌套的,用于本说明的目的。 ]被视为template-argument-list的结尾,而不是大于运算符。
结果是:
const_cast
但是,在C ++ 0x中,以下是规则
在名称查找(3.4)之后发现名称是模板名称,或者operator-function-id引用一组重载函数,其中任何成员都是函数模板,如果后跟一个{ {1}},
X<(16 > 1)> a; // works X<(int(16) > 1)> b; // works X<(16 >> 1)> c; // works X<(int(16) >> 1)> d; // works X<16 > 1> e; // fails X<int(16) > 1> f; // fails X<16 >> 1> g; // works (">>" is not a ">" token) X<int(16) >> 1> h; // works (">>" is not a ">" token).
始终被视为模板参数列表的分隔符,而不是小于运算符。解析模板参数列表时,第一个非嵌套&gt; [脚注:<
,其中包含<
,>
,dynamic_cast
或static_cast
的类型ID,或包含模板参数的为了本说明的目的,后续模板ID被认为是嵌套的。]被视为结束分隔符而不是大于运算符。类似地,第一个非嵌套reinterpret_cast
被视为两个连续但不同的const_cast
标记,其中第一个被视为模板参数列表的末尾并完成模板标识。< / p>
结果将是
>>
确保在测试时禁用C ++ 0x模式
答案 1 :(得分:2)
根据Stroustrup:“第一个非嵌套&gt;终止模板参数列表。如果需要大于号,则必须使用括号。”
因此,容忍第二组表达式的编译器不正确地执行; <{1}}失败的编译器是错误的。