在函数模板中创建一个containor迭代器

creating a containor iterator inside a function template

本文关键字:一个 containor 迭代器 函数模板 创建      更新时间:2023-10-16

代码是使用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在编译时是已知的,那么编译器已经知道T中的iterator是一个类(在我的情况下,T是vector<int>)。那么,为什么会出现错误呢?

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

更新:

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

处理此权限的正确编译器是Gcc。VC++将允许您编译格式错误的代码。使用Gcc编译时发生的错误是由于语法分析,因为Gcc会尝试解析函数模板的代码,但它会发现一个语法错误T::iterator it;,因为Deafault的Gcc将T::iterator视为变量(T::iterator被解析为非类型)而不是类型,要解决这个问题,必须明确地告诉Gcc,将T::iterator视为类型,这是通过添加关键字CCD_ 12来完成的
现在回到VC++。之所以能做到这一点,是因为VC++中存在错误,这是因为VCC++是否延迟了T::iterator是变量还是类型的决定。或者VC++在其认为需要的任何地方提供关键字CCD_ 14


有用的文章
注意:如果您发现不正确的地方,请随时编辑UPDATE。

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

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

考虑本文中的一个例子:

class ContainsAType {
   class iterator { ... }:
   ...
};
class ContainsAValue {
   static int iterator;
};

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

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

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

是的,这就是为什么VC++可以不使用typename关键字。

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

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

正如DeadMG所指出的,当编译器无法诊断缺失的类型名时,VC++的方法可能会失败,并产生更复杂的代码。

看看这个线程。

当编译器看到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编译这个代码)。