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

Sum*_*ant 9 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
 }
Run Code Online (Sandbox Code Playgroud)

为什么会出现这种不一致?标准允许/禁止的是什么?在vc9上使用BOOST_AUTO时,此类行为也会导致语法错误.在我看来,通过拒绝所有没有括号的表达式,Comeau正在做正确的工作.

Joh*_*itb 8

C++ 03的规则如下:

在名称查找(3.4)发现名称是模板名称后,如果此名称后跟a <,<则始终将其作为模板参数列表的开头,并且永远不会作为名称后跟小于运算符.当解析模板id,第一非嵌套>[脚音符:一个>包围的类型-ID dynamic_cast,static_cast,reinterpret_castconst_cast,或包围随后模板id的模板的参数,被认为是嵌套为目的这个描述.]被视为模板参数列表的结尾而不是大于运算符.

结果是:

  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). 
Run Code Online (Sandbox Code Playgroud)

但是,在C++ 0x中,以下是规则

在名称查找(3.4)之后发现名称是模板名称,或者operator-function-id引用一组重载函数,其中任何成员都是函数模板,如果后跟a <,<则始终为作为模板参数列表的分隔符,从不作为小于运算符.当解析模板参数列表中,第一个非嵌套> [脚音符:一个>包围的类型-ID dynamic_cast,static_cast,reinterpret_castconst_cast,或包围随后模板id的模板的参数,被认为是嵌套为了本说明的目的,将...作为结束分隔符而不是大于运算符.类似地,第一个非嵌套>>被视为两个连续但不同的>标记,其中第一个被视为template-argument-list的结尾并完成template-id.

结果将是

  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;        // fails (">>" translated to "> >")
  X<int(16) >> 1> h;   // fails (">>" translated to "> >")
Run Code Online (Sandbox Code Playgroud)

测试时一定要在comeau中禁用C++ 0x模式