5

Code is Compiled using GCC. This work without any error in VC++

template <typename T>
void Function(T& A){

  T::iterator it; //Error : dependent-name 'T::iterator' is parsed as a non-type,
                  //but instatiation yields a type.
}

This article states that the compiler can't figure out wether the iterator in T type is a class or just a static member. So we must use typename keyword to classify the symbol as a type.

My question is, since T is known at compile-time then the compiler already knows that iterator inside T is a class (in my case T is vector<int>). So why there is an error?

Also is this another use of the typename keyword beside using it as defining the template parameter T.

UPDATE:

I read all the answers and other answers from here which really answered all my thoughts. I can sum it up to this :

The correct compiler that handle this right is Gcc. VC++ will let you compile a malformed code. The Error that accure while compiling with Gcc is due to the syntax analysis, since Gcc will try to parse the code of the function template but it will find a syntax error which is T::iterator it; because Gcc by Deafault treats T::iterator as a variable (T::iterator is parsed as non-type) and not as a type, to solve this problem you must tell Gcc explicitly to treat T::iterator as a type, this is done by adding the keyword typename.
Now back to VC++. the answer to why this worked is because of existing bug in VC++, it's whether VC++ delay the decision of whether T::iterator is a variable or a type. or the VC++ supplies the keyword typename wherever it think it's required.


Useful Article
Note: Feel free to edit the UPDATE if you find something incorrect.

Community
  • 1
  • 1
AlexDan
  • 3,203
  • 7
  • 30
  • 46
  • 1
    Can you provide a link to the article? How about [this one](http://pages.cs.wisc.edu/~driscoll/typename.html) or [this other one](http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fkeyword_typename.htm)? – chrisaycock Aug 06 '12 at 03:26
  • Compiles and runs fine for me in VS2010 btw. – Aesthete Aug 06 '12 at 03:27
  • @chrisaycock : http://www.codeproject.com/Articles/268849/An-Idiots-Guide-to-Cplusplus-Templates-Part-2 – AlexDan Aug 06 '12 at 03:27
  • @Aesthete : yes I forgot to mention that it work with VC++ and some compilers but in Gcc and others, wont work. – AlexDan Aug 06 '12 at 03:28
  • @AlexDan That's a long article. Where in that article are you referring? – chrisaycock Aug 06 '12 at 03:29
  • @chrisaycock : search for this sentence: typename Container::const_iterator lcIter; – AlexDan Aug 06 '12 at 03:30
  • @Aesthete: The MSVC compiler accepts a lot of template code which it shouldn't (this being one example). See [here](http://stackoverflow.com/questions/6273176/what-exactly-is-broken-with-microsoft-visual-cs-two-phase-template-instanti) for some more info. – Jesse Good Aug 06 '12 at 03:30

3 Answers3

2

The article you refer to provides the explanation:

the compiler must be told that specified symbol is actually a type, and not a static symbol of given class.

Consider an example from this article:

class ContainsAType {
   class iterator { ... }:
   ...
};

class ContainsAValue {
   static int iterator;
};

So in your Function() above, the compiler must know whether T::iterator is a type or a static variable. The typename keyword removes that ambiguity in C++.

chrisaycock
  • 36,470
  • 14
  • 88
  • 125
  • well when I call "Function(ob)" and "ob" is of type "vector", then the compiler knows that "T" is a "vector" and "T::iterator" is a class not static variable. so where is the ambiguity here ? – AlexDan Aug 06 '12 at 03:46
  • @AlexDan The C++ **parser** doesn't know `T` is a vector. Imagine building the *abstract syntax tree* for the templated function. – chrisaycock Aug 06 '12 at 03:52
  • inside the template function "Function >" there is no "T" type, it got already replaced by "vector". so you can build the parse tree, correct me if I'm wrong. – AlexDan Aug 06 '12 at 04:00
  • @AlexDan The AST for `Function()` doesn't have an instance; it just has the template, which acts as a placeholder, if you will. The template instantiation wouldn't take place until the **semantic analysis** phase of compiling. – chrisaycock Aug 06 '12 at 04:02
  • the semantic analysis takes place when we specify the function with the underlying type, at this time "T" is known to be "vector". – AlexDan Aug 06 '12 at 04:27
  • 1
    @AlexDan C++ requires two-phase name look-up. Once a template definition time and once at template instantiation time. To make the first case work it has to be stated if the dependent name is a type or a value, because the information to deduce that is missing. MSVC simply doesn't conform and thus it seems to magically work. – pmr Aug 06 '12 at 07:42
1

This thread contains some good discussions about the use of typename in a similar case.

My question is, since T is known at compile-time then the compiler already knows that iterator inside T is a class (in my case T is vector).

Yes, this is why VC++ can do without the typename keyword.

So why there is an error?

Because the standard says that template name look-ups should be done in two phases. This requires disambiguation in some cases (see this). So the error comes about in GCC because it is compliant to the standard in repsect to two-phase name lookups. VC++ on the other hand uses a late-parsing scheme.

As DeadMG pointed out, VC++'s method can fail with more complex code when the compiler can't diagnose the missing typename.

Check out this thread as well.

Community
  • 1
  • 1
suchthat
  • 31
  • 4
  • Sometimes language design decisions are made for the sake of compiler implementers. – totowtwo Aug 06 '12 at 06:46
  • 3
    VC++ "solves" this problem by not conforming to the Standard insofar as two-phase lookup is concerned. This can yield problems in more complex template code. – Puppy Aug 06 '12 at 06:47
  • Can you refer me to an example of template code that VC++ has problems with? I've seen the possibility of failure mentioned elsewhere but I haven't been able to find any details regarding the circumstances that cause it to fail. – suchthat Aug 06 '12 at 11:55
0

When the compiler sees T::iterator it;, it doesn't know what T is yet. It will only know what T is when you call the function (instantiation time). This is part of two-phase name lookup, in the first phase, the compiler checks the declaration of Function for syntax errors and looks up all non-dependent names. This helps detect errors at the point of definition rather than waiting until the point of instantiation.

For example:

template <typename T>
struct A
{
    X x;
};

struct X{};

int main()
{
    A<int> a;
}

A good compiler will lookup X and tell you that it doesn't know what it is. However, the MSVC compiler will accept this malformed code.

Here is another example:

template <typename T>
class A : public I_do_not_exist
{
};

A good compiler will tell you I_do_not_exist doesn't exist (MSVC compiles this code).

Jesse Good
  • 50,901
  • 14
  • 124
  • 166