为什么C++;编译器需要一个";typename";在这种特殊情况下是什么关键字? 我刚刚发现C++在下面的代码中需要一个类型名(参见代码片段结尾的成员函数定义): 模板结构类WithSubtype { 结构子 { //静态无效检查(const ClassWithSubtype::Sub&Sub); ClassWithSubtype::Sub&operator=(常量ClassWithSubtype::Sub&other); }; }; /* /C++这里不需要参数类型的类型名 模板无效ClassWithSubtype::Sub::check(常量ClassWithSubtype::Sub&Sub) { //做某事。 } */ /这里C++需要返回类型的类型名 模板类型名称ClassWithSubtype::Sub&ClassWithSubtype::Sub::operator=(常量ClassWithSubtype::Sub&other) { //做某事。 } 我可以完全理解C++对于返回类型需要关键字类型名称< /C>。我不明白的是,为什么示例函数check(已注释掉)的参数类型不需要typename。此外,为什么赋值运算符的定义中需要类型名,而其声明中不需要。

为什么C++;编译器需要一个";typename";在这种特殊情况下是什么关键字? 我刚刚发现C++在下面的代码中需要一个类型名(参见代码片段结尾的成员函数定义): 模板结构类WithSubtype { 结构子 { //静态无效检查(const ClassWithSubtype::Sub&Sub); ClassWithSubtype::Sub&operator=(常量ClassWithSubtype::Sub&other); }; }; /* /C++这里不需要参数类型的类型名 模板无效ClassWithSubtype::Sub::check(常量ClassWithSubtype::Sub&Sub) { //做某事。 } */ /这里C++需要返回类型的类型名 模板类型名称ClassWithSubtype::Sub&ClassWithSubtype::Sub::operator=(常量ClassWithSubtype::Sub&other) { //做某事。 } 我可以完全理解C++对于返回类型需要关键字类型名称< /C>。我不明白的是,为什么示例函数check(已注释掉)的参数类型不需要typename。此外,为什么赋值运算符的定义中需要类型名,而其声明中不需要。,c++,C++,这两条规则(都在14.6.2.1中)一起产生了观察到的行为: 首先,那 名称引用当前实例化(如果是) 在定义类模板、类模板的嵌套类、类模板的成员或类模板的嵌套类的成员时,类模板或嵌套类的注入类名称(第9条) 在定义主要类模板或主要类模板的成员时,类模板的名称后跟主要模板的模板参数列表(如下所述) 包含在(或等效模板别名)中 在定义类模板的嵌套类时,作为模板引用的嵌套类的名称 当前实例化的成员,或 还有一个无关的要点 那么 名称是当前实例化的成员(如果是) 一种非限定名称,在查找时,该名称指

这两条规则(都在14.6.2.1中)一起产生了观察到的行为:

首先,那

名称引用当前实例化(如果是)

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

  • 在定义主要类模板或主要类模板的成员时,类模板的名称后跟主要模板的模板参数列表(如下所述) 包含在
    (或等效模板别名)中

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

还有一个无关的要点

那么

名称是当前实例化的成员(如果是)

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

因此,在这两种情况下,
ClassWithSubType
都引用当前实例化。但正如注释所解释的,
Sub
仅在类模板体中使用时才引用当前实例化的成员。在类外定义中,它成为“未知专门化的成员”

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


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

“当前实例化”和与之相关的复杂规则使声明能够工作。@Ben Voigt:但我希望它不依赖于编译器。。。换句话说:在声明中省略typename是否正确?那么函数参数呢???在类主体中,
typename
关键字不是必需的。基本上,在这些情况下,您甚至可以删除显式模板参数
。当我意识到这一点并开始看起来更像一个非依赖名称时,这对我来说是有意义的。@GuyGreer:你甚至可以说
Sub
,而无需进一步限定,因为它是注入的类名。
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.
}