Why Do I Need the "Typename" Keyword here?

Consider this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<iostream>
#include<vector>
using namespace std;


template <class T>
class MyClass
{
public:

   MyClass(unsigned gridSize)
   : mGridSize(gridSize)
   {
        mGrid = vector<vector<T>>(mGridSize);
        for (unsigned i = 0; i < mGridSize; ++i)
              mGrid[i] = vector<T>(i + 1);
   }

   typedef vector<vector<T>> Grid;

   typedef typename vector<vector<T>>::iterator itr1;  // A-OK!
   typedef          vector<vector<T>>::iterator itr2;  // error: missing ';' before identifier itr2

   typedef typename vector<vector<int>>::iterator itr3;  // A-OK!
   typedef          vector<vector<int>>::iterator itr4;  // A-OK!

   typedef typename vector<T>::iterator iter1;   // A-OK!
   typedef          vector<T>::iterator iter2;   // error: MyClass<T>::iter2 should be preceded by ;
   typedef typename vector<T>           type1;   // A-OK!
   typedef          vector<T>           type2;   // A-OK!

private:
   size_t mGridSize;
   vector<vector<T>> mGrid;
};


Why is keyword "typename" required when I try to typedef an iterator, but not the container itself?

The answer appears to have something to do with two things:

* Typedefing an iterator vs a non-iterator
* Typedefing a templated container vs concrete(right term?) container.
Last edited on
Thank you. I read those links and only half understand the problem.

 
typedef vector<T>::iterator iter2;


Here's what I think I understood:

The name "vector<T>::iterator" is a dependent name because it depends on the template parameter "N". Because it's a dependent name the compiler doesn't recognize it, so whether vector<T>::iterator is a type or an object is ambiguous.

I'm struggling to understand this better.

1. Why doesn't the typedef make it unambiguous? I thought that typedef produces aliases for types only.

2. Can you show me the two ways that the compiler can interpret that line of code? One where it's a type and one where it's an object?

3. The compiler obviously knew that, interpreted as an object the code is syntactically incorrect (I'm using Visual Studio and also compiling it with g++ on Linux... I think Visual Studio said that I was missing a ';' after the type name. So doesn't the fact that one interpretation produce an error and the other interpretation produces working code a good way to disambiguate things? (or is that the point of your 2nd link?)
> The name "vector<T>::iterator" is a dependent name because it depends on the template parameter

Yes.


> Because it's a dependent name the compiler doesn't recognize it, so whether
> vector<T>::iterator is a type or an object is ambiguous.

Because it's a dependent name (which is not part of the current instantiation MyClass<T>), during phase one, without the typename disambiguator, the compiler parses it as a non-type (this is the default).


> Can you show me the two ways that the compiler can interpret that line of code?
> One where it's a type and one where it's an object?

That is the point of Vandevoorde's proposal:
If X<T>::Y — where T is a template parameter — is to denote a type, it must be preceded by the keyword typename ; otherwise, it is assumed to denote a name producing an expression. There are currently two notable exceptions to this rule: base-specifiers and mem-initializer-ids.
...
Clearly, no typename is needed for this base-specifier because nothing but a type is possible in that context. However, there are several other places where we know only a type is possible and asking programmers to nonetheless specify the typename keyword feels like a waste of source code space (and is detrimental to readability).

The defining-type-id used in a typedef declaration must be the name of a type.

However, there are many situations where the disambiguator is required.
For examplewhere T is a template parameter, in the construct T::dependent name(0),
the dependent name could be either the name of a type (eg. a nested class)
or the name of a non-type (eg. a static member function)
Topic archived. No new replies allowed.