Typedef Foo <> Foo компилирует, но действительно ли он?

Следующий бит компиляции кода в VS2008 и GCC 4.8.2

template<typename T=void>
struct Foo
{
};

// typedef Foo<> Foo;   // Does *NOT* compile

int main()
{
    typedef Foo<> Foo;
    Foo f1;

   // Foo<char> f2;     // Does *NOT* compile
   //::Foo<char> f3;    // COMPILES
}

Действительно ли это?

Ответы

Ответ 1

В соответствии с С++ 11 3.3.10/1:

Имя может быть скрыто явным объявлением того же имени в вложенной декларативной области или производном класс.

(Акцент мой)

Вот почему имя шаблона Foo может быть скрыто с помощью typedef name Foo внутри main() (другая область), но не в той же области, в которой объявлено имя шаблона.

Относительно того, почему этот подобный случай является законным:

struct Foo
{
};

typedef Foo Foo;   // *DOES* compile

Это явно разрешено в 7.1.3/3:

В заданной неклассовой области спецификатор typedef может использоваться для переопределения имени любого типа, объявленного в этом для ссылки на тип, к которому он уже относится.

Ответ 2

Да, это действительно, по той же причине, что это действительно:

struct Foo { };

namespace bar {
    struct Foo { };
}

Вы просто переписываете имя в другой области. Внутри main вы все равно можете сделать что-то вроде:

::Foo<int> f2;