TonySalimi
TonySalimi

Reputation: 8427

Why typename keyword is not needed in template dependent nested type names in VS2015?

I was reading about the usage of typename in C++ template programming (e.g. this Q/A). To me, it seems that when using a dependent nested type name, we should use typename for avoiding parsing ambiguity. I also checked this on Scot Meyers book effective C++, item #42.

But what is strange for me is that the same example in the book, works without the typename. Here is the code:

template<class C>
void Print2nd(const C & cont)
{
   if (cont.size() >= 2)
   {
      C::const_iterator * iter1 = new C::const_iterator(cont.begin());  // why typename is NOT needed?
      C::const_iterator   iter2 = cont.begin();                         // why typename is NOT needed?
      (*iter1)++;
      iter2++;
      int value1 = **iter1;
      int value2 = *iter2;

      std::cout << "The value of 2nd with pointer is: " << value1 << std::endl;
      std::cout << "The value of 2nd without pointer is: " << value2 << std::endl;
   }
}


int main()
{
   std::vector<int> vect = {1,2,3,4,5,6};
   Print2nd(vect);
   return 0;
}

I am using VS2015. So, the Q is that why typename is not needed in this context? Is there any upgrade in recent C++ compilers to avoid using typename in such a context? Or I am doing a mistake in the code?

Update 1: Thanks to @FrançoisAndrieux comment, it seems that the same thing is happening in VS2008 and VS2010, as reported in this Q/A.

Upvotes: 3

Views: 280

Answers (2)

eerorika
eerorika

Reputation: 238331

typename is needed; the example program is ill-formed. If the compiler does not diagnose the issue, then it doesn't conform to the standard. A correct version is:

typename C::const_iterator * iter1 = new typename C::const_iterator(cont.begin());
                                      // ^^^^^^^^ this one only required until C++20
typename C::const_iterator   iter2 = cont.begin();

Standard quote (draft for C++17):

[temp.res]

A name used in a template declaration or definition and that is dependent on atemplate-parameteris assumednot to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.

C::const_iterator depends on the template-parameter C, so it should not be assumed to be a type name unless typename is used. I think the statement should be interpreted as a multiplication operation, but the right hand operand is undeclared identifier and thus ill-formed.

C++20 introduces rule that allows removing the typename from the new-expression (latest draft):

[temp.res]

A qualified name is said to be in a type-id-only context if it appears in a type-id, new-type-id, or defining-type-id and the smallest enclosing type-id, new-type-id, or defining-type-id is a new-type-id, defining-type-id, trailing-return-type, default argument of a type-parameter of a template, or type-id of a static_­cast, const_­cast, reinterpret_­cast, or dynamic_­cast.


You might want to create a type alias for readability:

using const_iterator = typename C::const_iterator;

Or you could just use auto:

auto it = cont.begin();

P.S. It hardly ever makes sense to dynamically allocate an iterator.

Upvotes: 4

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275385

In typename is not needed there. In some contexts, the need for typename was removed, because syntactically anything there must be a type.

In particular:

A qualified name that appears in type-id, where the smallest enclosing type-id is:

  • the type in a new expression that does not parenthesize its type;

Quoted source isn't directly from the standard, but pretty reliable.

Prior to typename was needed there; it would be parsed as a value, and new value is not valid syntax. In typename is optional in that context.

Now, has no features in it; what you are seeing there is MSVC's failure to properly implement //, not a extension.

Upvotes: 5

Related Questions