Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of typename keyword with typedef and new

Tags:

Consider this code,

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

In the above code, the keyword typename is required by the compiler, so that it can disambiguate between nested types and nested values in templates. That means, in the absence of typename keyword, compiler would interpret this as multiplication of T::X with x,

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

So in such situations where ambiguity can arise, the keyword typename becomes necessity so as to remove ambiguities. But there are few situations when the context itself removes ambiguities. The other topic discusses contexts of base-class and function-parameters (the latter doesn't remove ambiguity though). In this topic, I particularly want to discuss other two contexts which seem to be unambiguous, but we're still required 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 whatever follows is type, not value.

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


EDIT (after reading this response from Johannes Schaub) :

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

This syntax asks me to modify my question a little bit, so that the point which I'm trying to make, may be seen by others.

Consider this,

T::X typedef *x;

So from the context, it's still clear enough to the compiler that T::X is a type, no matter whether it appears before typedef,or after typedef. Unless C++ allows us to write typedef 5 five or typedef T::value t_value (where T::value is value), the presence of typedef itself removes all ambiguities and so, typename seems to be an unnecessary requirement by the Standard (in such situations). Same argument holds true for new as well.


Also, I've written a class template which is using this struct as template argument:

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

I particularly 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 complete code is here at ideone. Please have a look at it before replying. :-)

like image 300
Nawaz Avatar asked Dec 12 '10 10:12

Nawaz


People also ask

What is typedef typename?

typedef is defining a new type for use in your code, like a shorthand. typedef typename _MyBase::value_type value_type; value_type v; //use v. typename here is letting the compiler know that value_type is a type and not a static member of _MyBase . the :: is the scope of the 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.

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).

What is a typedef in C++?

typedef is a reserved keyword in the programming languages C and C++. It is used to create an additional name (alias) for another data type, but does not create a new type, except in the obscure case of a qualified typedef of an array type where the typedef qualifiers are transferred to the array element type.


1 Answers

C++ syntax is more crazy than that.

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

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

Others have commented about your example. The typename specifier does not yield to lookup ignoring non-type names. So if you say new typename T::X, and there is an object name X in T, it will still be found instead of the type name X (GCC however ignores non-type names in looking up a name after a typename. But that's not Standards compliant).


Answers to edits:

Consider this,

T::X typedef *x;

So from the context, it's still clear enough to the compiler that T::X is a type, no matter whether it appears before typedef,or after typedef.

The compiler has to know when the declaration specifiers and (i.e the "type section" and when the declarator section start (i.e 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 first name you specify is not a type, the type section ends, and the name section starts. Saying T::X tells the compiler:

Now I want to define T::X.

It reads from left to right, so it will think you forgot a semicolon when it then encounters the typedef. Inside classes the interpretation is slightly different but much like this too. That's a simple and effective parse.

Same argument holds true for new as well.

I tend to agree with you here. Syntactically it should be unambiguous if you leave off parentheses. As I've never written a C++ parser, there may be hidden pitfalls I'm not seeing, though.

Every addition of typename in corner cases of the language like in new will potentially require substantial amount of design for both compilers and standards writers, while still requiring typename for the vast majority of other cases where it's needed. I don't think that this pays off.

like image 93
Johannes Schaub - litb Avatar answered Oct 17 '22 08:10

Johannes Schaub - litb