在函数模板中创建容器迭代器

时间:2012-08-06 03:13:48

标签: c++ templates iterator

使用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
注意:如果发现错误,请随时编辑更新。

3 个答案:

答案 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编译这段代码)。