简体   繁体   English

同样关于typename和template关键字

[英]Again on typename and template keywords

I have carefully read many answers concerning this topic, but nevertheless I cannot figure out EXACTLY when these two keywords ARE or AREN'T needed in the scope of a non-template function which is member of a nested template class. 我已经仔细阅读了很多关于这个主题的答案,但是在非模板函数(嵌套模板类的成员)的范围内,当这两个关键字不需要这些关键字时,我无法弄清楚。

My reference compilers are GNU g++ 4.9.2 and clang 3.5.0. 我的参考编译器是GNU g ++ 4.9.2和clang 3.5.0。

They behave hardly different on the following code where I put embedded comments trying to explain what happens. 它们在下面的代码中几乎没有什么不同,我把嵌入的注释试图解释会发生什么。

#include <iostream>

// a simple template class with a public member template struct
template <class Z>
class Pa
{
// anything
public:
    template <class U>
    struct Pe  // a nested template
    {
        // anything
        void f(const char *); // a non-template member function
    };

    template <class U> friend struct Pe;
};

// definition of the function f
template <class AAA>
template <class BBB>
void Pa<AAA> :: Pe<BBB> :: f(const char* c)
{
    Pa<AAA> p; // NO typename for both clang and GNU...

    // the following line is ACCEPTED by both clang and GNU
    // without both template and typename keywords
    // However removing comments from typename only
    // makes clang still accepting the code while GNU doesn't
    // accept it anymore. The same happens if the comments   of template
    // ONLY are removed.
    //  
    // Finally both compilers accept the line when both typename AND
    // template are present...
    /*typename*/ Pa<AAA>::/*template*/ Pe<BBB> q;

    // in the following clang ACCEPTS typename, GNU doesn't:
    /*typename*/ Pa<AAA>::Pe<int> qq;

    // the following are accepted by both compilers
    // no matter whether both typename AND template
    // keywords are present OR commented out:
    typename Pa<int>::template Pe<double> qqq;
    typename Pa<double>::template Pe<BBB>  qqqq;
    std::cout << c << std::endl; // just to do something...
}

int main()
{
    Pa<char>::Pe<int> pp;
    pp.f("bye");
}

So, in the scope of f is Pa<double>::Pe<BBB> a dependent name or not? 那么,在f的范围内是否是Pa<double>::Pe<BBB>一个从属名称?

And what about Pa<AAA>::Pe<int> ? 那么Pa<AAA>::Pe<int>怎么样?

And, after all, why this different behaviour of the two quoted compilers? 毕竟,为什么两个引用编译器的这种不同行为?

Can anyone clarify solving the puzzle? 任何人都可以澄清解决难题吗?

The important rule in [temp.res] is: [temp.res]中的重要规则是:

When a qualified-id is intended to refer to a type that is not a member of the current instantiation (14.6.2.1) and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename , forming a typename-specifier . qualified-id旨在引用不是当前实例化成员的类型(14.6.2.1)并且其嵌套名称说明符引用依赖类型时,它应以关键字typename作为前缀,形成typename-specifier If the qualified-id in a typename-specifier does not denote a type, the program is ill-formed. 如果typename-specifier中的qualified-id不表示类型,则程序格式错误。

The question revoles around two qualified-id s: 这个问题围绕着两个合格身份

Pa<double>::Pe<BBB>
Pa<AAA>::Pe<int>

First, what is a dependent type? 首先,什么是依赖类型? According to [temp.dep.type]: 根据[temp.dep.type]:

A type is dependent if it is 如果是,则类型依赖于
— a template parameter, - 模板参数,
— a member of an unknown specialization, - 未知专业的成员,
— a nested class or enumeration that is a dependent member of the current instantiation, - 作为当前实例化的从属成员的嵌套类或枚举,
— a cv-qualified type where the cv-unqualified type is dependent, - cv-qualified类型所依赖的cv限定类型,
— a compound type constructed from any dependent type, - 由任何依赖类型构成的复合类型,
— an array type whose element type is dependent or whose bound (if any) is value-dependent, - 一个数组类型,其元素类型是依赖的或其边界(如果有)是依赖于值的,
— a simple-template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent, or - 一个simple-template-id ,其中模板名称是模板参数,或者任何模板参数是依赖类型或依赖于类型或依赖于值的表达式,或者
— denoted by decltype ( expression ), where expression is type-dependent (14.6.2.2). - 由decltype表达式 )表示,其中表达式依赖于类型(14.6.2.2)。

Pa<double> (the nested-name-specifier of the first example) is not a dependent type, as it fits none of the bullet points. Pa<double> (第一个示例的嵌套名称说明符 )不是依赖类型,因为它不适合任何项目符号。 Since we don't meet that criteria, we don't need to prefix the typename keyword. 由于我们不符合该标准,因此我们不需要为typename关键字添加前缀。

Pa<AAA> , however, is a dependent type since it is a simple-template-id in which one of the template arguments is a dependent type ( AAA is trivially a dependent type since it is a template parameter). 但是, Pa<AAA> 一个依赖类型,因为它是一个simple-template-id ,其中一个模板参数是一个依赖类型( AAA通常是一个依赖类型,因为它是一个模板参数)。

What, then, is "a member of the current instantiation"? 那么,什么是“当前实例化的成员”?

A name refers to the current instantiation if it is 名称是指当前实例化(如果是)
— [...] - [...]
— in the definition of a primary class template or a member of a primary class template, the name of the class template followed by the template argument list of the primary template (as described below) enclosed in <> (or an equivalent template alias specialization)" — in the definition of a nested class of a class template, the name of the nested class referenced as a member of the current instantiation, or - 在主类模板的定义或主类模板的成员中,类模板的名称后跟<>中包含的主模板的模板参数列表(如下所述)(或等效的模板别名专用) )“ - 在类模板的嵌套类的定义中,作为当前实例化的成员引用的嵌套类的名称,或者

The current instantiation, in this case, is Pa<AAA> (or, also, Pa ). 在这种情况下,当前实例化是Pa<AAA> (或者也是Pa )。 And: 和:

A name is a member of the current instantiation if it is [...] A qualified-id in which the nested-name-specifier refers to the current instantiation and that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. 名称是当前实例化的成员,如果它是[...] qualified-id ,其中嵌套名称说明符引用当前实例化,并且当查找时,引用类的至少一个成员这是当前实例化或其非依赖基类。

So Pe is a member of the current instantiation. 所以Pe是当前实例化的成员。 Thus, while the nested-name-specifier of Pa<AAA>::Pe<int> is a dependent type, it is a type that is a member of the current instantiation, so you do not need the keyword typename . 因此,虽然Pa<AAA>::Pe<int>嵌套名称说明符是依赖类型,但它是一个类型,它是当前实例化的成员,因此您不需要关键字typename Note that Pa<AAA>::Pe<int> is a dependent type itself (it's a nested class that is a dependent member of the current instantiation), but that in itself does mean that the typename keyword is required. 请注意, Pa<AAA>::Pe<int>本身一个依赖类型(它是一个嵌套类,它是当前实例化的依赖成员),但这本身就意味着需要typename关键字。

The fact that gcc doesn't accept typename here: gcc在这里不接受typename这一事实:

/*typename*/ Pa<AAA>::Pe<int> qq;

because it wants 因为它想要

typename Pa<AAA>::template Pe<int> qq;

is a bug. 是个bug。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM