为什么关键字"typename"需要在合格的依赖名称之前,而不是在合格的独立名称之前?

xcr*_*ypt 17 c++ templates typename

class A
{
   static int iterator;
   class iterator
   {
      [...]
   };
   [...]
};
Run Code Online (Sandbox Code Playgroud)

我(我想)理解为什么typename需要这里:

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

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

void foo() {
   A::iterator* iter;
   [...]
}
Run Code Online (Sandbox Code Playgroud)

谁能解释一下?


编辑:

编译器之所以没有后者的问题,我发现在评论中得到了很好的回答:

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种不同类型将具有不同的含义,这是不可接受的."

Ker*_* SB 41

C++中的名称可以涉及三个不同的实体层:值,类型和模板.

struct Foo
{
    typedef int A;
    static double B;
    template <typename T> struct C;
};
Run Code Online (Sandbox Code Playgroud)

这三个名字Foo::A,Foo::B并且Foo::C是三个不同层次的例子.

在上面的例子中,Foo是一个完整的类型,因此编译器已经知道Foo::A等等.但现在想象一下:

template <typename T> struct Bar
{
    T::A x;
};
Run Code Online (Sandbox Code Playgroud)

现在我们遇到麻烦了:是什么T::A?如果T = Foo,那么T::A = int,哪种类型,一切都很好.但是什么时候T = struct { char A; };,这T::A是一个没有意义的价值.

因此,编译器的需求是告诉它T::A,并T::BT::C认为是.如果你什么都不说,那就假定它是一个值.如果你说typename,它是一个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);
    }
};
Run Code Online (Sandbox Code Playgroud)

二次检查,如是否T::B可以转换为int,是否ax可以成倍增加,以及是否C<int>真的有成员函数gobble都推迟,直到你真正实例化的模板.但是,名称表示值,类型或模板的规范是代码语法正确性的基础,必须在模板定义期间提供.

  • @xcrypt,有几个方面,编译器需要考虑.例如,`T :: A*x;`,对于`T :: A`是一个类型而`T :: A`是一个值的情况,这个表达式可以是真的.如果`A`是一个类型,那么它将导致指针声明; 如果`A`是一个值,那么它将导致乘法运算.因此,单个"模板"对于2种不同的类型将具有不同的含义,这是不可接受的.因此,我们需要明确提及它是否是一种类型. (4认同)