5

代码使用 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.
}

本文指出编译器无法确定T类型中的迭代器是类还是静态成员。所以我们必须使用typename关键字来将符号分类为一个类型。

我的问题是,由于T在编译时已知,因此编译器已经知道iteratorT 内部是一个类(在我的情况下是 T vector<int>)。那么为什么会出现错误呢?

typename除了将其用作定义模板参数之外,这也是关键字的另一种用途T

更新:

我从这里阅读了所有答案和其他答案,它们真正回答了我的所有想法。我可以总结为:

处理这个权利的正确编译器是 Gcc。VC++ 将允许您编译格式错误的代码。使用 Gcc 编译时产生的错误是由于语法分析,因为 Gcc 会尝试解析函数模板的代码,但它会发现语法错误,这是T::iterator it;因为 Gcc by Deafault 将T::iterator其视为变量(T::iterator被解析为非type) 而不是作为类型,要解决此问题,您必须明确告诉 Gcc 将T::iterator其视为类型,这是通过添加关键字来完成的typename
现在回到 VC++。为什么这个工作的答案是因为 VC++ 中存在的错误,这是 VC++ 是否延迟决定是否T::iterator是变量或类型。或者 VC++typename在它认为需要的地方提供关键字。


有用的文章
注意:如果您发现不正确的内容,请随时编辑更新。

4

3 回答 3

2

您参考的文章提供了解释:

必须告诉编译器指定的符号实际上是一种类型,而不是给定类的静态符号。

考虑这篇文章中的一个例子:

class ContainsAType {
   class iterator { ... }:
   ...
};

class ContainsAValue {
   static int iterator;
};

所以在你Function()上面,编译器必须知道T::iterator是类型还是静态变量。该typename关键字消除了 C++ 中的歧义。

于 2012-08-06T03:37:12.247 回答
1

这个线程包含一些关于在类似情况下使用 typename 的很好的讨论。

我的问题是,由于 T 在编译时是已知的,那么编译器已经知道 T 内部的迭代器是一个类(在我的情况下 T 是向量)。

是的,这就是 VC++ 可以不用 typename 关键字的原因。

那么为什么会出现错误呢?

因为标准规定模板名称查找应分两个阶段完成。在某些情况下,这需要消除歧义(参见this)。因此错误出现在 GCC 中,因为它符合两阶段名称查找的标准。另一方面,VC++ 使用后期解析方案。

正如 DeadMG 指出的那样,当编译器无法诊断丢失的类型名时,VC++ 的方法可能会因更复杂的代码而失败。

也看看这个线程

于 2012-08-06T04:24:59.777 回答
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 编译这段代码)。

于 2012-08-06T04:32:41.683 回答