views:

671

answers:

5

A friend and I were discussing C++ templates. He asked me what this should do:

#include <iostream>

template <bool>
struct A {
    A(bool) { std::cout << "bool\n"; }
    A(void*) { std::cout << "void*\n";  }
};

int main() {
    A<true> *d = 0;
    const int b = 2;
    const int c = 1;
    new A< b > (c) > (d);
}

The last line in main has two reasonable parses. Is 'b' the template argument or is "b > (c)" the template argument?

Although, it is trivial to compile this, and see what we get, we were wondering what resolves the ambiguity?

A: 

The greediness of the lexer is probably the determining factor in the absence of parentheses to make it explicit. I'd guess that the lexer isn't greedy.

Ben Collins
But isn't the lexing completely unambiguous?
Rob Rolnick
It will error out on ambiguity, so yes. Being greedy or non-greedy doesn't make you ambiguous. Greediness is actually a way to resolve ambiguity. You also get into the interaction between the lexer and the parser in this case, so maybe it's the parser that's not greedy.
Ben Collins
The grammar may be ambiguous, but the lexer is absolutely not. The spacing makes the lexer completely well defined.
Rob Rolnick
I agree with you. I never said the lexer is ambiguous.
Ben Collins
+3  A: 

AFAIK it would be compiled as new A<b>(c) > d. This is the only reasonable way to parse it IMHO. If the parser can't assume under normal circumstances a > end a template argument, that would result it much more ambiguity. If you want it the other way, you should have said new A<(b > c)>(d);.

Leon Timmermans
A: 

I'm unable find the relevant passage in the standard but I believe Leon is right. In this case of ambiguity, parenthesises around the expression inside the template argument list are required.

Konrad Rudolph
+3  A: 

The C++ standard defines that if for a template name followed by a <, the < is always the beginning of the template argument list and the first non-nested > is taken as the end of the template argument list. If you intended that the result of the > operator be the template argument, then you'd need to enclose the expression in parens. You don't need parens if the argument was part of a static_cast<> or another template expression.

Lee Baldwin
+3  A: 

As stated by Leon & Lee, 14.2/3 (C++ '03) explicitly defines this behaviour.

C++ '0x adds to the fun with a similar rule applying to '>>'. The basic concept, is that when parsing a template-argument-list a non nested '>>' will be treated as two distinct '>' '>' tokens and not the right shift operator:

template <bool>
struct A {
  A(bool);
  A(void*);
};

template <typename T>
class C
{
public:
  C (int);
};

int main() {
    A<true> *d = 0;
    const int b = 2;
    const int c = 1;
    new C <A< b  >>  (c) > (d); // #1
    new C <A< b > >  (c) > (d); // #2
}

'#1' and '#2' are equivalent in the above.

This of course fixes that annoyance with having to add spaces in nested specializations:

C<A<false>> c;  // Parse error in C++ '98, '03 due to "right shift operator"
Richard Corden