Interestingly, C suffers from a somewhat similar ambiguity, where not the results of runtime-at-compile-time but rather type definitions affect the parsing.
In C++, the problem becomes so bad that the language designers capitulated in some instances, and you have to tell the compiler if something is a type or an identifier. Haven't tested this example, but you get the point:
struct test
{
typedef int bar;
};
template <class T> struct foo
{
typename T::bar x; // if you leave off 'typename', it won't compile
};
foo<test> y;
y.x = 5;
What I don't quite understand is why, if it won't compile in the first place (i.e. there is no ambiguity, just correct or incorrect), you need to specify it in the first place. I suspect it somehow makes compiler implementation easier.
It's not about making compiler implementations easier -- it's about protecting template authors against having someone write:
class MyBadClass {
static int bar;
};
foo<MyBadClass> y;
By writing "typename", the template author can indicate that "T::bar" the template author can indicate that "bar" is expected to be a type, not a variable. This is explained in more detail here: http://pages.cs.wisc.edu/~driscoll/typename.html.
Now the parse is ambiguous. While the language could say "you only need to use typename if the declaration would otherwise be ambiguous," it's simpler and more consistent to say "all qualified dependent types must use typename."
...you have to know whether InnerDef is a type or a number. If it's a type, this is a declaration of a pointer y. If it's a number, it's a multiplication which is then discarded.
The problem is that to know whether InnerDef is a type or a number you have to instantiate Template<params>. But C++ templates are Turing-complete: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.14.3...), so performing this instantiation would be undecidable except that C++ defines a recursion depth limit.