views:

397

answers:

3

I have Vertex template in vertex.h. From my graph.h:

20 template<class edgeDecor, class vertexDecor, bool dir>
21 class Vertex;

which I use in my Graph template.

I've used the Vertex template successfully throughout my Graph, return pointers to Vertices, etc. Now for the first time I am trying to declare and instantiate a Vertex object, and gcc is telling me that my 'declarator' is 'invalid'. How can this be?

81 template<class edgeDecor, class vertexDecor, bool dir>
82 Graph<edgeDecor,int,dir> Graph<edgeDecor,vertexDecor,dir>::Dijkstra(vertex s, bool print = false) const
83 {
84    /* Construct new Graph with apropriate decorators */
85    Graph<edgeDecor,int,dir> span = new Graph<edgeDecor,int,dir>();
86    span.E.reserve(this->E.size());
87
88    typename Vertex<edgeDecor,int,dir> v = new Vertex(INT_MAX);
89    span.V = new vector<Vertex<edgeDecor,int,dir> >(this->V.size,v);
90 };

And gcc is saying:

graph.h: In member function ‘Graph<edgeDecor, int, dir> Graph<edgeDecor, vertexDecor, dir>::Dijkstra(Vertex<edgeDecor, vertexDecor, dir>, bool) const’:
graph.h:88: error: invalid declarator before ‘v’
graph.h:89: error: ‘v’ was not declared in this scope

I know this is probably another noob question, but I'll appreciate any help.

+4  A: 

Probably needs to be

Vertex<edgeDecor,int,dir> v = new Vertex(INT_MAX);

because you are declaring an instance of Vertex. typename keyword is only valid inside template parameter list.

Thanks Abhay and outis for pointing out valid uses of keyword outside the template parameter list.

After having another look at the code a number of other things come to mind:

  1. As pointed out by Mike Dinsdale you are missing template parameters here: new Vertex(INT_MAX);. Try Vertex<edgeDecor,int,dir> instead.
  2. You are assigning a pointer to a class instance. If you are creating it on the stack it should be something like this:

    Vertex v(INT_MAX);

If creating on the heap v must be pointer type:

Vertex<edgeDecor,int,dir>* v = new Vertex<edgeDecor,int,dir>(INT_MAX);
Igor Zevaka
"typename keyword is only valid inside template parameter list", i don't think so. For template-dependent names, most compilers require you to specify *typename*.
Abhay
RE dependent names: read http://pages.cs.wisc.edu/~driscoll/typename.html. In the OP's case, `Vertex<edgeDecor,int,dir>` isn't a dependent typename, so `typename` isn't valid.
outis
Without the "typename" keyword gcc gives: graph.h:88: error: expected type-specifier before ‘Vertex’Which makes me think "typename" is required here to indicate to the compiler that I'm referring to a type.
nieldw
Does the "expected type-specifier before 'Vertex'" refer to the second Vertex, after the "new"? It looks like you might need template arguments here...?
Mike Dinsdale
@mike-dinsdale: Yes, that was it, thanks.@gman: Cool, typename is out. But Re int -> vertexDecor, I specifically want to return a Graph for which the vertex decorator should be an int. I specified it that way in my function prototype too. How should I rather do that?
nieldw
@outis, `Vector<edgeDecor, int, dir>` surely is a dependent name. But it's not qualified. `typename` can only applied to *qualified* names (and those are not needed to be dependent. You might say `typename string::size_type s;` just fine).
Johannes Schaub - litb
+1  A: 

Igor is right. As for the following error:

graph.h:88: error: expected type-specifier before ‘Vertex’ 

... you probably need to say:

Vertex<edgeDecor,int,dir> v = new Vertex<edgeDecor,int,dir>(INT_MAX);
Vulcan Eager
That solved it. Thanks.
nieldw
A: 

As said, it's a problem of misplaced typename first.

Some examples:

template <class T>
struct MyClass
{
  struct Foo { static int MBar; };
};

template <>
struct MyClass<int> { static int Foo; };

Using MyClass:

template <class T>
void useMyClass(T t)
{
  MyClass<T> c;
}

There is no need of typename because there is no ambiguity, the compiler knows MyClass got to be a type here.

template <class T>
void useFoo(T t)
{
  typename MyClass<T>::Foo f;
}

We need to disambiguate because the compiler does not know in advance if the Foo symbol will be a type, a method or an attribute. Indeed, if T == int this code is erroneous since Foo would represent a static attribute instead of being a struct!

void useFoo(int t)
{
  int f = MyClass<int>::Foo;
}

void useFoo(float t)
{
  float f = MyClass<float>::Foo::MBar;
}

Here typename is not required: since the compiler knows all the types in the template parameter list, it can instantiate the template class for MyClass<int> and MyClass<float> and as for a regular class knows the inside-out of each instantiation (and in particular what each symbol does represent).

template <class T>
void useBar(T t)
{
  int i = typename MyClass<T>::Foo::MBar;
}

Once again we need typename because Foo is a type and the compiler needs to know it.

If you don't really get it, don't worry. The typename and template keywords sometimes creep in in unusual places in generic code: just wait for the compiler error to begin with, you'll soon memorize the kind of errors and correct them in a wink.

Matthieu M.