29
template <int>
using A = int;

void f(A<0>=0);   // Attempting to declare a function f taking int,
                  // with the default argument 0

// Works as expected:
// void f(A<0> = 0);

This neither compiles on GCC 4.9.2 nor Clang 3.5 - let alone ICC or VC++. Apparently the >= bit is parsed as a greater-or-equal-than operator. However, this seems to be incorrect regarding [temp.names]/3:

After name lookup (3.4) finds that a name is a template-name or that an operator-function-id or a literal- operator-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 >138 is taken as the ending delimiter rather than a greater-than operator. [..] [ Example:

template<int i> class X { /* ...*/ };

X< 1>2 > x1; // syntax error
X<(1>2)> x2; // OK

— end example ]

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

Am I missing something or is this a compiler bug?

Columbo
  • 57,033
  • 7
  • 145
  • 194
  • 1
    For reasons I do not understand at all, on gcc 4.7.3, the compile error is "too few arguments to function `void f(A<1>)`." – Barry Feb 05 '15 at 21:18
  • 8
    `>=` does not involve the greater-than operator. It is the greater-than-or-equal operator, which is a different token. Some efforts where made to make `foo< a>` work (see the `>>` there?) to be treated like `foo< a >`, but maybe not for `>=`. I'd start by figuring out where the changes to the standard that made `foo>` work, and reverse engineer the problem from that? – Yakk - Adam Nevraumont Feb 05 '15 at 21:19
  • 2
    Isn't this just the maximal much rule and this case needs a special exception like [this one](http://stackoverflow.com/a/24977313/1708801) – Shafik Yaghmour Feb 05 '15 at 21:20
  • Yakk said it a bit, but when it's being parsed the compiler will read it as >=(because compilers are lazy) and because no one would necessarily think of the importance of adding a conditional to see if the > matches a < until a user(like you) reports it, and thus bugs would frequently occur. So yes __I__ would say it is a bug but other people may disagree. – tom Feb 05 '15 at 21:22
  • This problem was actually noted in [N1757](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html), the paper adding the special fix for `>>`. – T.C. Feb 06 '15 at 10:12
  • @T.C. you now I read that last night before I went to sleep and I skipped right over that paragraph, otherwise I would have added it earlier. – Shafik Yaghmour Feb 06 '15 at 10:26

1 Answers1

20

This an effect of the maximal munch principle, which has the lexical analyzer take as many characters as possible to form a valid token. This is covered in draft C++ standard section 2.5 [lex.pptoken] which says:

Otherwise, the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token, even if that would cause further lexical analysis to fail.

Any cases such as the one you cite above need a specific exception carved out such as this case for <::, we can see an example in the following code:

template<typename T> class SomeClass;
class Class;

SomeClass<::Class>* cls;

which is covered in this question, the exception is listed in the bullet just above the maximal munch rule:

Otherwise, if the next three characters are <:: and the subsequent character is neither : nor >, the < is treated as a preprocessor token by itself and not as the first character of the alternative token <:.

and of course the non-nested > which you cite in your question.

Note we can see that >= is a preprocessor token from section 2.13 [lex.operators] which says:

The lexical representation of C++ programs includes a number of preprocessing tokens which are used in the syntax of the preprocessor or are converted into tokens for operators and punctuators:

and includes >= in the list.

The >> fix

We can see from the proposal that fixed the >> case: N1757: Right Angle Brackets which says (emphasis mine):

Ever since the introduction of angle brackets, C++ programmers have been surprised by the fact that two consecutive right angle brackets must be separated by whitespace:

#include <vector>
typedef std::vector<std::vector<int> > Table;  // OK
typedef std::vector<std::vector<bool>> Flags;  // Error

The problem is an immediate consequence of the the “maximum munch” principle and the fact that >> is a valid token (right shift) in C++.

This issue is a minor, but persisting, annoying, and somewhat embarrassing problem. If the cost is reasonable, it seems therefore worthwhile to eliminate the surprise.

The purpose of this document is to explain ways to allow >> to be treated as two closing angle brackets, as well as to discuss the resulting issues. A specific option is proposed along with wording that would implement the proposal in the current working paper.

Also points out the >= case:

It is also worth noting that the problem can also occur with the >>= and >= tokens. For example

void func(List<B>= default_val1);
void func(List<List<B>>= default_val2);

Both of these forms are currently ill-formed. It may be desirable to also address this issue, but this paper does not propose to do so.

Note, this change broke backward compatibility with C++03.

Community
  • 1
  • 1
Shafik Yaghmour
  • 143,425
  • 33
  • 399
  • 682