为什么非类型模板参数表达式处理在编译器之间不一致?

时间:2009-10-20 16:29:51

标签: c++ compiler-construction templates

这是我在各种编译器中观察到的内容。似乎存在编译器错误。

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通过拒绝所有没有括号的表达式来做正确的工作。

2 个答案:

答案 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_caststatic_cast的类型ID,或包含模板参数的为了本说明的目的,后续模板ID被认为是嵌套的。]被视为结束分隔符而不是大于运算符。类似地,第一个非嵌套reinterpret_cast被视为两个连续但不同的const_cast标记,其中第一个被视为模板参数列表的末尾并完成模板标识。< / p>

结果将是

>>

确保在测试时禁用C ++ 0x模式

答案 1 :(得分:2)

根据Stroustrup:“第一个非嵌套&gt;终止模板参数列表。如果需要大于号,则必须使用括号。”

因此,容忍第二组表达式的编译器不正确地执行; <{1}}失败的编译器是错误的。