代码之家  ›  专栏  ›  技术社区  ›  Sumant

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

  •  9
  • Sumant  · 技术社区  · 16 年前

    这是我在各种编译器中观察到的一些东西。似乎有编译器错误。

    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 回复  |  直到 16 年前
        1
  •  8
  •   Johannes Schaub - litb    16 年前

    规则如下:C++ 03:

    在名称查找之后(3.4)发现名称是模板名称,如果该名称后面跟有 < , the < 始终作为模板参数列表的开头,从不作为名称后跟小于运算符。分析模板ID时,第一个非嵌套的 > [脚注:A > 包含的类型ID dynamic_cast , static_cast , reinterpret_cast 或 const_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). 
    

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

    在名称查找(3.4)后,如果名称后面跟着一个 < , the < 始终作为模板参数列表的分隔符,从不作为小于运算符。在分析模板参数列表时,第一个非嵌套的 > 包含的类型ID 动态铸件 ,请 静态铸造 , 重新解释铸模 或 康斯特卡斯特 或包含后续模板ID的模板参数的,被视为为此说明而嵌套。]被视为结束分隔符,而不是大于运算符。同样,第一个非嵌套 >> 被视为两个连续但不同的 > 标记,其中第一个标记作为模板参数列表的结尾,并完成模板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 "> >")
    

    在测试中一定要禁用C0+0X模式

        2
  •  2
  •   moonshadow    16 年前

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

    因此,允许第二组表达式的编译器做得不正确;在 X<(int(16) >> 1)> d; 是马车。