使用GCC编译代码。这项工作在VC ++中没有任何错误
template <typename T>
void Function(T& A){
T::iterator it; //Error : dependent-name 'T::iterator' is parsed as a non-type,
//but instatiation yields a type.
}
This article表明编译器无法弄清楚T
类型中的迭代器是类还是静态成员。因此,我们必须使用typename
关键字将符号归类为类型。
我的问题是,由于T
在编译时是已知的,因此编译器已经知道T中的iterator
是一个类(在我的例子中T是vector<int>
)。那么为什么会有错误?
另外,typename
关键字的另一种用法是将其用作定义模板参数T
。
更新:
我阅读了 here 的所有答案和其他答案,这些答案真正回答了我的所有想法。我可以总结一下:
处理此权利的正确编译器是Gcc。 VC ++将允许您编译格式错误的代码。使用Gcc编译时产生的错误是由于语法分析,因为Gcc将尝试解析函数模板的代码,但它会发现T::iterator it;
的语法错误,因为Deafault的Gcc会对{{1}进行处理作为一个变量(T::iterator
被解析为非类型)而不是一个类型,为了解决这个问题,您必须明确告诉Gcc将T::iterator
视为一种类型,这可以通过添加关键字来完成T::iterator
。
现在回到VC ++。为什么这有效的答案是因为VC ++中存在的错误,VC ++是否会延迟typename
是变量还是类型的决定。或VC ++提供关键字T::iterator
,只要它认为是必需的。
Useful Article
注意:如果发现错误,请随时编辑更新。
答案 0 :(得分:2)
您所引用的文章提供了解释:
必须告诉编译器指定的符号实际上是一个类型,而不是给定类的静态符号。
考虑来自this article的示例:
class ContainsAType {
class iterator { ... }:
...
};
class ContainsAValue {
static int iterator;
};
因此,在上面的Function()
中,编译器必须知道T::iterator
是类型还是静态变量。 typename
关键字消除了C ++中的歧义。
答案 1 :(得分:1)
This thread包含了一些关于在类似情况下使用typename的讨论。
我的问题是,因为T在编译时已知,所以编译器已经知道T中的迭代器是一个类(在我的例子中T是向量)。
是的,这就是为什么VC ++可以不使用typename关键字。
那么为什么会出现错误?
因为标准说模板名称查找应该分两个阶段完成。这在某些情况下需要消除歧义(see this)。因此,错误在GCC中出现,因为它符合重新定位到两阶段名称查找的标准。另一方面,VC ++使用后期解析方案。
正如DeadMG指出的那样,当编译器无法诊断丢失的类型名时,VC ++的方法会因代码更复杂而失败。
同时查看this thread。
答案 2 :(得分:0)
当编译器看到T::iterator it;
时,它不知道T
是什么。它只会在调用函数时知道T
是什么(实例化时间)。这是两阶段名称查找的一部分,在第一阶段,编译器检查Function
的声明是否存在语法错误,并查找所有非依赖名称。这有助于在定义点检测错误,而不是等到实例化之后。
例如:
template <typename T>
struct A
{
X x;
};
struct X{};
int main()
{
A<int> a;
}
一个好的编译器会查找X
并告诉你它不知道它是什么。但是,MSVC编译器将接受此格式错误的代码。
这是另一个例子:
template <typename T>
class A : public I_do_not_exist
{
};
一个好的编译器会告诉你I_do_not_exist
不存在(MSVC编译这段代码)。