Ответ 1
В соответствии с С++ 11 3.3.10/1:
Имя может быть скрыто явным объявлением того же имени в вложенной декларативной области или производном класс.
(Акцент мой)
Вот почему имя шаблона Foo
может быть скрыто с помощью typedef name Foo
внутри main()
(другая область), но не в той же области, в которой объявлено имя шаблона.
Относительно того, почему этот подобный случай является законным:
struct Foo
{
};
typedef Foo Foo; // *DOES* compile
Это явно разрешено в 7.1.3/3:
В заданной неклассовой области спецификатор
typedef
может использоваться для переопределения имени любого типа, объявленного в этом для ссылки на тип, к которому он уже относится.