“typename” and “template” keywords: are they really necessary?

允我心安 提交于 2019-11-29 05:09:29

The rule is: typename has to be used whenever a name that depends on a template parameter is a type. There are clear cases where it's needed, consider

template <typename T> 
class Foo { 
    typename T::type * p; 
    //... 
}; 

Here, the second typename is used to indicate that type is a type defined within class T. Thus, p is a pointer to the type T::type.

Without typename, type would be considered a member of class T. So the expression:

T::type * p

would be a multiplication of the type member of class T with p.

Similarly, the rule is: .template, ->template or ::template must be used when accessing a template member that uses a template parameter. Consider:

 p->template SomeMethod<int>(x);

without the use of template, the compiler does not know that the < token is not less-than but the start of a template argument list.

By definition, it is impossible to write code which differs in meaning with or without the keyword; any attempt to do so will result in undefined behavior. The only purpose of these keywords (at least in this context) is to allow the compiler to fully parse the template before instantiation: in order to correctly parse C++, the compiler must know whether a symbol designates a type, a template or something else.

Once you instantiate the template, the compiler no longer really needs the keywords; they have no impact on name lookup, or anything else. The only particularity is that if the name found puts a lie to your declaration (you said type, and in the instantiation, it isn't a type), undefined behavior occurs. If, for example, the compiler has stored the template in the form of a parse tree, this parse tree will be incorrect, and who knows what that might imply.

I would expect that most good compilers would note the category in the first parse, and if name lookup returns something else, emit an error, but for historical reasons, I suspect that there are still compilers which more or less ignore the template or typename in this context, treating it as a comment; store the template as a sequence of tokens, and only parse once the template is instantiated, using the categories it actually finds in the instantiation.

EDIT:

I've been rereading parts of the standard, and I'm no longer sure that there is undefined behavior. C++11, at least, says:

A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified." by the keyword typename.

When a qualified-id is intended to refer to a type that is not a member of the current instantiation and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename, forming a typename-specifier. If the qualified-id in a typename-specifier does not denote a type, the program is ill-formed.

Ill-formed usually (but not always) requires a diagnostic. (As mentioned above, I would expect a compiler to issue a diagnostic in any case.)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!