Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 762
Sumant Avatar asked Oct 20 '09 16:10

Sumant


1 Answers

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

like image 92
Johannes Schaub - litb Avatar answered Mar 23 '23 20:03

Johannes Schaub - litb