为什么C ++编译器在这种特殊情况下需要“typename”关键字?

时间:2015-03-11 19:30:39

标签: c++

我刚才发现C ++在下面的代码中需要一个typename(请参阅代码片段末尾的成员函数定义):

template <typename T> struct ClassWithSubtype
{
    struct Sub
    {
        //static void check( const ClassWithSubtype<T>::Sub& sub );
        ClassWithSubtype<T>::Sub& operator=( const ClassWithSubtype<T>::Sub& other );
    };
};

/*
//Here C++ does not require a typename for the argument type
template <typename T> void ClassWithSubtype<T>::Sub::check( const ClassWithSubtype<T>::Sub& sub )
{
    //do sth.
}
*/

//Here C++ requires a typename for the return type
template <typename T> typename ClassWithSubtype<T>::Sub& ClassWithSubtype<T>::Sub::operator=( const ClassWithSubtype<T>::Sub& other )
{
    //do sth.
}

我完全可以理解C ++需要关键字typename作为返回类型。我不明白的是为什么示例函数typename的参数类型(注释掉)需要NO check。此外,为什么在赋值运算符的定义中需要typename,而不是在其声明中?

1 个答案:

答案 0 :(得分:2)

这两个规则(均在14.6.2.1中)产生观察到的行为:

首先,那个

  

名称是指当前实例化,如果它是

     
      
  • 在类模板的定义,类模板的嵌套类,类模板的成员或类模板的嵌套类的成员中,注入类名(第9条)类模板或嵌套类

  •   
  • 在主类模板或主类模板成员的定义中,类模板的名称后跟主模板的模板参数列表(如下所述)   括在<>(或等效的模板别名专门化),

  •   
  • 在类模板的嵌套类的定义中,嵌套类的名称被引用为   当前实例化的成员,或

  •   

还有一个不相关的要点。

然后,

  

如果名称是

,则该名称是当前实例化的成员      
      
  • 一个非限定名称,当查找时,指的是当前实例化或其非依赖基类的类的至少一个成员。 [注意:只有在类模板定义所包含的范围内查找名称时才会出现这种情况。 - 结束注释]
  •   

和两个不相关的要点。

因此,在这两种情况下,ClassWithSubType<T>都指当前的实例化。但正如本说明所解释的那样,Sub仅在类模板体内使用时才引用当前实例化的成员。在课外定义中,它成为未知专业化的成员&#34;。

作为当前实例化的成员,编译器确定Sub是类类型。

在类体之外,编译器不知道这一点,并且需要typename关键字。