As per C++11 3.3.10/1:
A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived
class.
(Emphasis mine)
That's why the template name Foo
can be hidden by the typedef name Foo
inside main()
(a different scope), but not in the same scope as the template name is declared.
As to why this similar case is legal:
struct Foo
{
};
typedef Foo Foo; // *DOES* compile
That is explicitly allowed by 7.1.3/3:
In a given non-class scope, a typedef
specifier can be used to redefine the name of any type declared in that
scope to refer to the type to which it already refers.