tags:

views:

367

answers:

3

Why does the following code give me an error (g++ 4.1.2)?

template<class A>
class Foo {
public:
  typedef std::vector<A> AVec;
  AVec* foo();
};

template<class A>
Foo<A>::AVec* Foo<A>::foo() { // error on this line
  return NULL;
}

The error is:

error: expected constructor, destructor, or type conversion before '*' token

How am I supposed to define the Foo<A>::foo() function otherwise (with the correct return type)?

A: 

I don't really know, but try putting the typedef outside of the class.

Javier Badia
+7  A: 

This is an issue called "two-stage lookup". Basically, since A is a template parameter in foo()'s definition, the compiler can't know when parsing the template for the first time, whether Foo<A>::AVec is a type or even exists (since, for instance, there may exist a specialization of Foo<Bar> which doesn't contain the typedef at all). It will only know what it is during template instantiation, which happens later - and it's too late for this stage.

The correct way would be to use the typename keyword to indicate that this is a type:

template<class A>
class Foo {
public:
  typedef std::vector<A> AVec;
  AVec* foo();
};

template<class A>
typename Foo<A>::AVec* Foo<A>::foo() {
  return NULL;
}
ASk
Your solution is correct, but I'm not so sure about the explanation. As soon as the compiler reaches 'Foo<A>::foo' it will go back and "fix" the return type. If it did not do this it would not match the declaration of 'foo' (in the class) with the definition (ie. it would warn that the return types were different). This has nothing to do with 'two-stage' lookup as per your link.
Richard Corden
I believe that I was mistaken in the two-stage lookup link. The correct explanation is - when looking up a nested dependent name (one that relies on an unknown template parameter, i.e Foo<A>::Bar), it's assumed to be not a type. The only exception is during base classes list.As for the compiler fixing up the return type - no, template instantiation happens much later; the error is received during the first scan that is done by the compiler on the code
ASk
+3  A: 

The usual typename issue:

template<class A>
typename Foo<A>::AVec* Foo<A>::foo() { // error on this line
  return NULL;
}

Remember: All qualified names that depend on a template parameter need typename before them.

Johannes Schaub - litb