Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of typename keyword with template function parameters

In C++, the typename keyword is needed so the compiler can disambiguate between nested types and nested values in templates. However, there are certain situations where no ambiguity is possible, such as when a derived class inherits from a nested class type.

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

Here the typename keyword is not required, and is in fact not even allowed. This makes sense, because the context removes the ambiguity. Here, T::type must refer to a type, since you obviously can't inherit from a value.

I would think the same thing would hold 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 a type, since a function parameter can't be a value. Yet, the compiler doesn't accept this. It wants const typename T::type&. This seems inconsistent. Why does the language allow the 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 the need for typename in one but not the other?

like image 527
Channel72 Avatar asked Dec 03 '10 16:12

Channel72


People also ask

What is typename in template?

" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.

What is use of typename keyword in C++?

Use the keyword typename if you have a qualified name that refers to a type and depends on a template parameter. Only use the keyword typename in template declarations and definitions.

Which keyword can be used in template class or typename?

C++ adds two new keywords to support templates: 'template' and 'typename'. The second keyword can always be replaced by keyword 'class'.

Why is typename needed?

The typename keyword is needed whenever a type name depends on a template parameter, (so the compiler can 'know' the semantics of an identifier (type or value) without having a full symbol table at the first pass).


3 Answers

If you slightly change your declaration, you get an entire different story

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

That isn't unambiguous anymore. It could declare a variable of type void that is initialized by a bit-wise AND expression. The entire declaration would be templated. Of course, this semantically is all nonsense, but it syntactically is alright.

The appearance of a single const syntactically makes it unambiguous, but it's too much context dependence to make this work in a compiler. It has to remember that it read a const or any other such thing, and when it parses the T::type after it will need to remember to take this name as a type. It would also further bloat the already complicated Standard beyond belief.

Let's again change your function declaration

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

Not even the appearance of const in there provides for a unambiguous parse. Should it be a function declaration with an unnamed parameter, or should it be a function declaration with an invalid parameter name that misses its type? A parameter's name is parsed by a declarator-id, which can also be a qualified name. So here, the const will belong to the type specifiers, while the T::type will be parsed by the compiler as the name of the parameter, in absence of a typename. That is totally nonsense too, but is syntactically valid.

In the case of base-class names name lookup itself states that non-type names are ignored. So you get omission of typename for free: The name that name lookup yields to more higher level modules of the compiler either refers to a type, or name lookup will have given an error.

I have written a FAQ entry about Where to put the "template" and "typename" on dependent names.

like image 77
Johannes Schaub - litb Avatar answered Oct 23 '22 15:10

Johannes Schaub - litb


Firstly, I don't think there ever was an intent to make a sharp and precise distinction between the situations where only typenames are allowed (like base class name) and situations where non-type entities are allowed as well (like expressions). I'd say that the base class name context was singled out for some other reason.

Secondly, it is not exactly correct to say that in function parameter declarations every entity is necessarily a 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 dictates that type must be a typename and value must be a value. However, the compiler can only figure that out after the syntactic analysis of the declaration, while I believe the idea of typename was introduced to aid the compiler in actually starting the proper syntactic analysis of the code, i.e. the distinction should be available before the syntactic analysis, as an input into the syntactic analysis. This distinction might have profound effects on the interpretation of the code.

like image 5
AnT Avatar answered Oct 23 '22 16:10

AnT


Would be interesting to find what is causing this.

I've been trying to read the standard in search for an answer, please note I'm am novice in this.

However I believe I've found a relevant clause.

§14.6.2. 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.

I guess this implies that the issue is in the difference of how name lookup works for base specifier lists and function arguments.

Base specifier name lookup:

§10.2. During the lookup for a base class name, non-type names are ignored (3.3.10).

Which explains why typename is not required for base specifiers.

Still looking for function argument name lookup.

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

The error given by VS2010 when not qualifying the template argument in the function declaration is the following:

'T::type' : dependent name is not a type prefix with 'typename' to indicate a type.

However, I'm still unclear about the rules for dependent function argument name lookup...

like image 2
ronag Avatar answered Oct 23 '22 15:10

ronag