Why is non-type template parameter expression handling inconsistent across compilers?

c++, compiler-construction, templates

Solution

The rules are as follows for C++03:

After name lookup (3.4) finds that a name is a template-name, if this name is followed by a `<`, the `<` is always taken as the beginning of a template-argument-list and never as a name followed by the less-than operator. When parsing a template-id, the first non-nested `>` [foot-note: A `>` that encloses the type-id of a `dynamic_cast`, `static_cast`, `reinterpret_cast` or `const_cast`, or which encloses the template-arguments of a subsequent template-id, is considered nested for the purpose of this description. ] is taken as the end of the template-argument-list rather than a greater-than operator.

So the result is:

  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). 

However, in C++0x the following are the rules

After name lookup (3.4) finds that a name is a template-name, or that an operator-function-id refers to a set of overloaded functions any member of which is a function template, if this is followed by a `<`, the `<` is always taken as the delimiter of a template-argument-list and never as the less-than operator. When parsing a template-argument-list, the first non-nested > [foot-note: A `>` that encloses the type-id of a `dynamic_cast`, `static_cast`, `reinterpret_cast` or `const_cast`, or which encloses the template-arguments of a subsequent template-id, is considered nested for the purpose of this description.] is taken as the ending delimiter rather than a greater-than operator. Similarly, the first non-nested `>>` is treated as two consecutive but distinct `>` tokens, the first of which is taken as the end of the template-argument-list and completes the template-id.

Result will be

  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 "> >")

Be sure to disable C++0x mode in comeau when testing

Problem

Here is something I observed across various compilers. It seems there are compiler bugs. ``` 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 } ``` Why is that inconsistency? What is allowed/disallowed by the standard? Such behavior is also responsible for syntax error while using BOOST_AUTO on vc9. It appears to me that Comeau is doing the right job by rejecting all the expressions without parenthesis.

Original source