Using the typename keyword with typedef and new

Consider this code,

template<class T> struct Sample { typename T::X *x; //declare pointer to TX }; 

In the code above, the typename keyword requires a compiler so that it can resolve the ambiguity between nested types and nested values ​​in templates. This means that in the absence of the typename keyword, the compiler interprets this as multiplying T :: X by x,

 T::X *x; //multiply T::X with x 

Therefore, in situations where ambiguity may arise, the typename keyword becomes a necessity to eliminate ambiguity. But there are several situations where the context itself removes ambiguities. another topic discusses the contexts of the base class and functional parameters (the latter does not eliminate ambiguity). In this section, I especially want to discuss the other two contexts that seem unambiguous , but we still need to write typename ,

 typedef typename T::X xtype; pX = new typename T::X; 

In these two situations, the keywords typedef and new make it clear enough to the compiler that all that follows is the type, not .

So my question is: why do compilers still need the typename keyword, even in unambiguous situations, for example, when we use typedef and new ?




EDIT (after reading this answer from Johannes Schaub ):

 //typedef NOT followed by a type! int typedef A; 

This syntax asks me to slightly modify my question, so that the point I'm trying to make may be noticed by others.

Consider this,

 T::X typedef *x; 

So, from the context it is still clear enough for the compiler that T :: X is a type, regardless of whether it appears before a typedef or after a typedef . If C ++ does not allow us to write typedef 5 five or typedef T::value t_value (where T :: value is a value), the presence of typedef itself removes all the ambiguities, and therefore typename seems to be an unnecessary standard requirement (in such situations) . The same argument holds true for new .




In addition, I wrote a class template that uses this structure as a template argument:

 struct A { struct X { string name; }; static const int X = 100; }; 

I especially want to know if the following code (from the constructor) is correct (portable) or not,

 //two interesting statements pX = new typename T::X; //T::X means struct X product = T::X * p; //but here, T::X means int X 

The full code is here on ideone. Please take a look at it before replying. :-)

+19
c ++ language-lawyer typedef templates typename
Dec 12 '10 at 10:53
source share
3 answers

The C ++ syntax is more crazy.

 // typedef NOT followed by a type! int typedef A; // new NOT followed by a type! new (0) int; 

Others commented on your example. The typename does not search, ignoring non-type names. Therefore, if you say new typename T::X , and there is an object name X in T , it will still be found instead of a name of type X (however, GCC ignores non-type names when searching for a name after typename , but this does not meet the standards).




Responses to changes:

Consider this,

 T::X typedef *x; 

So, from the context, it is still clear enough for the compiler that T :: X is a type, regardless of whether it appears before a typedef or after a typedef.

The compiler must know when the declaration specifiers and (that is, the type section and when the declarator section begins (for example, the names section). There are declarations where the type section is empty:

 // constructor definitions don't need a type section MyClass::MyClass() { } // conversion function definitions don't need a type section MyClass::operator int() { } 

If the name you specified is not a type, the type section ends and the name section begins. A T::X statement tells the compiler:

Now I want to define T::X

It reads from left to right, so it will think that you forgot the semicolon when it encounters a typedef . Inside the classes, the interpretation is slightly different, but also the same. This is a simple and effective analysis.

The same argument holds true for the new.

I tend to agree with you here. Syntactically, this should be unambiguous if you leave parentheses. Since I never wrote a C ++ parser, there may be hidden traps that I don't see.

Each addition of typename to corner cases of the language, as in new , will potentially require a significant amount of design for both compilers and authors of standards, while still requiring typename for the vast majority of other cases when necessary, I don’t think it pays off .

+14
Dec 12 2018-10-12
source share

Then why do compilers still need the typename keyword?

Since the rules of the language are formulated in this way: each dependent name that is used in the type context must be preceded by typename (mutatis mutandis, the same holds for the template name and keyword template ). So, why do language rules not matter between cases where a type name is required to eliminate ambiguity and those where the context provides sufficient information? I probably was not there when the decision was made - that the content of the language description was even more complex (consider the consequences of the missing cases, one way or another).

In your example, X is not a type name (this feature, if for compatibility with C, where the tag name is not automatically a type name), so you need yuse struct :

 pX = new struct T::X; 
0
Dec 12 '10 at 11:26
source share

Your code seems to fall into a very gray area.

This paragraph is about hiding the name

The name of the class (9.1) or the name of the enumeration (7.2) can be hidden by the name of a variable, data element, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data element, function or enumerator are declared in the same (in any order) with the same name, class or enumeration name hidden wherever the variable, data is the name of the member, function or counter name.

seems to indicate that the compiler is right to complain that A::X not a type name.

0
Dec 12 '10 at 11:26
source share



All Articles