Reputation: 8427
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
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
Reputation: 275385
In c++20 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 c++20 typename
was needed there; it would be parsed as a value, and new value
is not valid syntax. In c++20 typename
is optional in that context.
Now, visual-studio-2015 has no c++20 features in it; what you are seeing there is MSVC's failure to properly implement c++11/c++14/c++17, not a c++20 extension.
Upvotes: 5