Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Template Ambiguity

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?

like image 663
Rob Rolnick Avatar asked Sep 09 '08 18:09

Rob Rolnick


3 Answers

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 written:

new A<(b > c)>(d);
like image 146
Leon Timmermans Avatar answered Nov 19 '22 01:11

Leon Timmermans


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"
like image 25
Richard Corden Avatar answered Nov 19 '22 01:11

Richard Corden


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 parentheses. You don't need parentheses if the argument was part of a static_cast<> or another template expression.

like image 3
Lee Baldwin Avatar answered Nov 19 '22 01:11

Lee Baldwin