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.

Constructs with Right Angle Brackets

The example above shows the most common context of double right angle brackets: Nested template-ids. However, the “new-style” cast syntax may also participate in such constructs. For example:

However, if template aliases make it into the language (and it seems likely
they will), then template-ids will be able to represent nonclass types.
It seems therefore desirable to address the issue for all constructs with
right angle brackets, not just for templates.

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

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.

Possible Solutions

Solving our problem amounts to decreeing that under some circumstances
a >> token is treated as two right angle brackets
instead of a right shift operator. As it turns out, there are several
general approaches to defining those
“circumstances.”

Approach 1.
The first approach is the simplest: Decree that if a left angle bracket is
active (i.e. not yet matched by a right angle bracket) the >> token
is treated as two right angle brackets instead of a shift operator,
except within parentheses or brackets that are themselves within the angle brackets.
A slight
variation on that theme (call it “Approach 1b”) is to
require at least two left angle brackets to
be active since otherwise the construct would be an error (because there would be an excess of right angle brackets).

This strategy is similar to the treatment of the > token:
If a left angle bracket is active, the token is treated as a right angle
bracket, except within parentheses. For example:

A<(X>Y)> a; // The first > token appears within parentheses and
// therefore is not a right angle bracket. The second one
// is a right angle bracket because a left angle bracket
// is active and no parentheses are more recently active.

Unfortunately, some programs may be broken by this approach.
Consider the following example:

With the right angle bracket rule proposed above, the >> token
in the second statement would change its meaning (from right shift to double right
angle bracket) and the output would therefore
become:

0
0

Approach 2.
To avoid the backward incompatibility, an alternative solution it to modify
the rule proposed above to only treat the >> token as two right
angle brackets when parsing template type arguments or template template
arguments, but not when parsing template nontype arguments. This approach would make A<B<int>> valid, but would leave C<D<12>> ill-formed.

Another way to view this alternative approach is that a template argument
is always parsed as far as possible (which may include right shift operators).
When an argument is parsed, the next token must be a comma, a >
treated as a single closing angle bracket, or (with this proposal) a
>> token treated as a double angle bracket.

Approach 3.
Finally, a third way to tackle the problem is to eliminate the right shift
token altogether and to modify the grammar so that two consecutive
> tokens are treated as a right shift operation in the appropriate circumstances. This would for example allow the following form:

int i = 10000 > > x;

If limited to the right shift token, this approach introduces no known
new ambiguities, but it does introduce at least one backward compatibility
issue: The ## preprocessing token can no longer be applied to two
> tokens. However, it would be surprising to eliminate the
right shift token and not the left shift token. Eliminating the left
shift token does introduce new parsing ambiguities
(e.g., &X::operator<<Y>).
The shift-assign operators (<<= and >>=)
lead to similar considerations. It may also come as a surprise that
shift operations are realized through a two-token construct, whereas
other operations (e.g., prefix and postfix --, or &&)
use a single two-character token.

Implementation Experience

Approach 1.
As mentioned, the first proposal is analogous to the existing language
rule for the > token. We therefore do not expect implementation difficulty for the approach.

Approach 2.
The GNU and EDG C++ compilers currently implement the second proposed
alternative for error recovery purposes. It would be trivial to promote
the error recovery procedure to a correct parse procedure. (Other compilers
appear to have a facility for the same purpose, but I do not know their exact
strategy.)

Recommendation

I suggest we pursue “Approach 1” (which breaks some valid programs).
Specifically, I propose that if even a single left angle bracket is active,
a >> token not enclosed in parentheses is treated as two
right angle brackets and not as a right shift operator. I do not
recommend the variation described as “Approach 1b.”

My arguments for doing so are the following:

It leaves no remaining cases that require whitespace between
two right angle brackets, which makes teaching easier.

It treats the >> token in the same way as the >
token, making both specification and teaching simpler.

Programs that would change meaning are probably as contrived as the
example shown above, and therefore unlikely to be found in nature. Programs that would become ill-formed (i.e., containing a nonparenthesized right-shift operator in a trailing nontype template argument) are probably slightly more common but still rare.

(While the approach of eliminating the shift tokens (approach 3) was presented for the
sake of completeness, I find that it has enough small technical and
aesthetic problems to make the other approaches far preferable.)

Wording changes

Insert after the last normative sentence of 14.2/3, but before the example:

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. [ Note: The second > token produced by this replacement rule may terminate an enclosing template-id construct or it may be part of a different construct (e.g., a cast). --end note ]

Insert just before the first "Note:" of translation phase "7." in 2.1/1:

[ Note: The process of analyzing and translating the tokens may occasionally result in one token being replaced by a sequence of other tokens (14.2 temp.names). --end note ]

Insert a new paragraph 5.2/2 that reads:

[ Note: The > token following the type-id in a dynamic_cast, static_cast, reinterpret_cast, or const_cast, may be the product of replacing a >> token by two consecutive > tokens (14.2 temp.names). --end note ]

Insert in 14/1 just after the grammar rules:

[ Note: The > token following the template-parameter-list of a template-declaration may be the product of replacing a >> token by two consecutive > tokens (14.2 temp.names). --end note ]

Append to 14.1/1 (following the grammar rules):

[ Note: The > token following the template-parameter-list of a type-parameter may be the product of replacing a >> token by two consecutive > tokens (14.2 temp.names). --end note ]