我正在玩Visual Studio和模板。
考虑这段代码
struct Foo
{
struct Bar
{
};
static const int Bar=42;
};
template<typename T>
void MyFunction()
{
typename T::Bar f;
}
int main()
{
MyFunction<Foo>();
return 0;
}
当我编译它是Visual Studio 2008和11时,我收到以下错误
error C2146: syntax error : missing ';' before identifier 'f'
Visual Studio在这方面是否正确?代码是否违反任何标准?
如果我将代码更改为
struct Foo
{
struct Bar
{
};
static const int Bar=42;
};
void SecondFunction( const int& )
{
}
template<typename T>
void MyFunction()
{
SecondFunction( T::Bar );
}
int main()
{
MyFunction<Foo>();
return 0;
}
它编译时没有任何警告。在Foo :: BLAH中,成员首选类型,以防发生冲突?
关于G ++ 4.2.1的EDIT测试
struct Foo
{
static const int Bar=42;
};
void SecondFunction(const int& x)
{
}
template<typename T>
void MyFunction()
{
int x = Foo::Bar;
}
int main()
{
MyFunction<Foo>();
return 0;
}
编译好。
struct Foo
{
static const int Bar=42;
};
void SecondFunction(const int& x)
{
}
template<typename T>
void MyFunction()
{
SecondFunction(T::Bar);
}
int main()
{
MyFunction<Foo>();
return 0;
}
给我这些错误
未定义的符号: “Foo :: Bar”,引自: void cck498aS.o中的MyFunction() ld:找不到符号 collect2:ld返回1退出状态
答案 0 :(得分:3)
在C ++中,命名实体属于三个不同的本体层之一:值,类型和模板。
如果从属名称是未知层,那么你必须告诉编译器它是什么:
如果你什么都不说,那就是一个价值。
如果你说typename
,那就是一种类型。
如果你说template
,那就是模板。
因此T::Bar
作为MyFunction
模板中的从属名称,会自动被假定为引用某个值,因此int
成员Foo::Bar
。另一方面,在第一个示例中,typename T::Bar
确实是指成员类型 Foo::Bar
。
答案 1 :(得分:3)
您会看到存在C兼容性的不为人知的规则的效果。在C中,与C ++不同,如果将类型定义为struct X
或enum X
,则不将名称X
引入相应的命名空间,但是将类型称为struct X
。因此,在C中,您还可以将“X”定义为不同的东西,而不会触发相互冲突的定义。现在在C ++中,struct X
确实将名称X
引入相应的范围。因此,X
的任何其他定义都将被标记为双重定义。但是,能够包含经常出现此问题的C标头被认为是重要的。因此,引入了一条特殊规则,即只要您同时拥有X
的(非typedef)类型定义和X
的另一个定义,这不会导致错误,但X
引用对于非类型定义,要获得类型定义,您必须在其前面加上相应的类型关键字(即struct X
,emum X
或class X
)。
在您的情况下,这意味着Foo
包含名为class Bar
的类型和名为Bar
的静态const int,但没有名为Bar
的类型。请注意,此处不需要模板;一个简单的全局声明Bar::Foo foo;
也应该失败。