Using the typename keyword with template function parameters

In C ++, the typename keyword is required so that the compiler can resolve the ambiguity between nested types and nested values ​​in templates. However, there are certain situations where ambiguity is impossible, for example, when a derived class is inherited from a nested class type.

 template <class T> class Derived : public T::type { }; 

Here the typename keyword is not required and is actually not even allowed. This makes sense because context removes ambiguity. Here T::type must refer to the type, since you obviously cannot inherit from the value.

I would think that the same is true for function template parameters.

 template <class T> void foo(const T::type& v) { } 

In this case, the context makes it clear that T::type must refer to the type, since the function parameter cannot be a value. However, the compiler does not accept this. He wants const typename T::type& . This seems inconsistent. Why does the language allow an implicit assumption of a nested type in the context of inheritance, but not in the context of function parameters? In both cases, there can be no ambiguity, so why do we need typename in one and not the other?

+28
c ++ templates typename
Dec 03 '10 at 16:38
source share
3 answers

If you slightly change your expression, you will get a completely different story

 template <class T> void foo(T::type& v); 

This is no longer unique. It can declare a variable of type void , which is initialized with the bit expression AND . The whole declaration will be conceived. Of course, this is semantically all nonsense, but syntactically it’s good.

Syntactically, the appearance of one const syntax makes it unambiguous, but there is too much contextual dependency to make this work in the compiler. He must remember that he read const or any other such thing, and when he parses T::type after he needs to remember that name as a type. It would also further inflate an already complex Standard without faith.

Change the function declaration again

 template <class T> void foo(const T::type); 

Even the appearance of const in it does not provide unambiguous analysis. Should it be a function declaration with an unnamed parameter, or should it be a function declaration with an invalid parameter name that skips its type? The parameter name is parsed using declarator-id , which can also be a qualified name. So, here const will belong to type specifiers, and T::type will be parsed by the compiler as a parameter name, in the absence of typename . This is also complete nonsense, but syntactically valid .

In the case of base class name names, the name lookup itself claims that non-type names are ignored. Thus, you get typename inaction for free: a name that the search name returns to higher-level compiler modules either refers to the type, or the search for the name would give an error.

I wrote an entry in the FAQ about Where to put "template" and "typename" in dependent names .

+22
Dec 03 '10 at 17:31
source share

First, I don’t think that there has ever been an intention to make a sharp and precise distinction between situations in which only type names (for example, the name of a base class) are allowed and situations in which non-peak entities (for example, expressions) are allowed. I would say that the context of the base class name was highlighted for another reason.

Secondly, it’s not entirely correct to say that in the declarations of function parameters, each entity is necessarily typename. You can declare a parameter as follows

 template <class T> void foo(const T::type& v[T::value]); 

Of course, the grammar in this case explicitly indicates that type must be typename and value must be a value. However, the compiler can only understand this after parsing the declaration, while I believe that the idea of typename was introduced to help the compiler actually start the correct parsing of the code, i.e. the difference should be available before parsing, like input to parsing. This difference can have a profound effect on code interpretation.

+4
Dec 03 '10 at 17:34
source share

It would be interesting to find out what causes this.

I am trying to read the standard in search of an answer, note that I am new to this.

However, I believe that I have found a proposal.

Β§14.6.2. The name used in the declaration or definition template, and depending on the template parameter, it is assumed that the type should not be specified unless the search for a suitable name finds the type name or name keyword typename .

I assume this means that the problem is the difference in how the name lookup works for the list of database qualifiers and function arguments.

Search for the base qualifier name:

Β§ 10.2. When searching for a base class name, non-type names are ignored (3.3.10).

This explains why typename is not required for basic specifications.

Search for the name of the function argument.

Please correct me if this is an incorrect or inconsequential assumption. In the meantime, I keep digging.

The error set by VS2010 when the template argument does not qualify in the function declaration is as follows:

'T :: type': dependent name is not type prefix type 'typename' specify type.

However, I still do not understand the rules for finding the dependent name of a function argument ...

+2
Dec 03 '10 at 17:06
source share



All Articles