2014-10-17 40 views
15

下面的代码位在VS2008和GCC 4.8.2编译typedef Foo <> Foo编译但它有效吗?

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

您正在模板中提供默认参数。这是完全有效的。 – 2014-10-17 18:29:41

+2

@Captain:但是他们都被命名为'Foo'的事实呢? – Cameron 2014-10-17 18:30:15

回答

17

按照C++ 11 3.3.10/1:

名称可以由同一个名字的一个明确的声明被隐藏一个嵌套声明区域或派生 类。

(重点煤矿)

这就是为什么模板名称Foo可以通过typedef名称Foomain()隐藏(不同的范围),但不是在相同的范围内模板名称声明。

至于为什么这种类似的例子是合法的:

struct Foo 
{ 
}; 

typedef Foo Foo; // *DOES* compile 

这由7.1.3/3被明确允许:

在给定的非类范围,一个typedef符可以是用于重新定义该 范围内声明的任何类型的名称,以指向其已引用的类型。

+4

+1引用规范! – 2014-10-17 19:50:10

+1

3.3.1 [basic.scope.declarative]/p4也是相关的。 – 2014-10-17 22:12:30

11

是它是有效的,出于同样的原因,这是有效的:

struct Foo { }; 

namespace bar { 
    struct Foo { }; 
} 

你只是在不同的范围覆盖了名。里面的主,你仍然可以这样做:

::Foo<int> f2; 
+0

啊,typename shadowing。如何美味偷偷摸摸:O – Cameron 2014-10-17 18:33:51

+0

我认为这个答案不对 - 有一个模板Foo取代了typedef(在一个命名空间中) – 2014-10-17 18:37:14

+0

@DieterLücking为什么?我可以很容易地创建一个'int Foo = 7;'这只是一个名字。 – Barry 2014-10-17 18:40:35

相关问题