为什么关键字"typename"在限定的从属名称之前需要,而不是在限定的独立名称之前?

Why is the keyword "typename" needed before qualified dependent names, and not before qualified independent names?

本文关键字:独立 关键字 为什么 typename      更新时间:2023-10-16
class A
{
   static int iterator;
   class iterator
   {
      [...]
   };
   [...]
};

我(想我)理解这里需要typename的原因:

template <class T>
void foo() {
   typename T::iterator* iter;
   [...]
}

但是我不明白为什么这里不需要typename:

void foo() {
   A::iterator* iter;
   [...]
}

谁能解释一下?


编辑:

编译器对后者没有问题的原因,我发现在注释中回答得很好:

A::iterator的情况下,我不明白为什么编译器不会将其与static int iterator混淆?——xcrypt

@xcrypt因为它知道A::iterator是什么,并且可以根据使用方式选择哪一个- Seth Carnegie


编译器在限定依赖名之前需要typename的原因,在我看来,Kerrek SB在接受的答案中回答得很好。一定要阅读对该答案的评论,特别是iammilind:

"T::A * x;,当T::A是类型且T::A是值时,此表达式可以为真。如果A是一个类型,那么它将导致指针声明;如果A是一个值,那么它将导致乘法。因此,一个模板对于2个不同的类型会有不同的含义,这是不可接受的。"

c++中的名称可以属于三个不同的实体层:类型、值和模板。

struct Foo
{
    typedef int A;                   // type
    static double B;                 // value
    template <typename T> struct C;  // template
};

三个名称Foo::A, Foo::BFoo::C是所有三个不同层的例子。

在上面的例子中,Foo是一个完整的类型,所以编译器已经知道Foo::A等指的是什么。但是现在想象一下:

template <typename T> struct Bar
{
    T::A x;
};

现在我们有麻烦了:T::A是什么?如果是T = Foo,则是T::A = int,这是一个类型,一切正常。但是当T = struct { static char A; };时,则T::A,这没有意义。

因此,编译器要求告诉它T::AT::BT::C是什么假定是什么。如果你什么都没说,它就被认为是一个值。如果输入typename,它是一个类型名,如果输入template,它是一个模板:
template <typename T> struct Bar
{
    typename T::A x;    // ah, good, decreed typename
    void foo()
    {
        int a = T::B;   // assumed value, OK
        T::template C<int> z;  // decreed template
        z.gobble(a * x);
    }
};

次要检查,如T::B是否可转换为int, ax是否可以相乘,以及C<int>是否真的有一个成员函数gobble,这些都被推迟到您实际实例化模板时。但是,名称是否表示值、类型或模板的规范是代码语法正确性的基础,必须在模板定义期间提供。

因为在非模板foo中,您正在执行有效的乘法操作(假设您在该操作之前声明了iter)。如果尝试省略星号,就会出现编译错误。int隐藏了类。

typename关键字而不是阻止隐藏。只有gcc不正确地实现了它。因此,如果您尝试用A作为类型实例化您的函数模板,那么得到编译错误,因为在typenake 之后指定的名称将在任何符合标准的编译器上引用非类型。

因为编译器在模板实例化之前不知道T::iterator是什么,所以它不知道iterator是一个类变量、类型、函数还是什么。您需要通过使用typename来告诉它它是一个类型。