Reputation: 8408
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.
Upvotes: 5
Views: 7416
Reputation: 300149
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.
Upvotes: 0
Reputation: 76570
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:
new Vertex(INT_MAX);
. Try Vertex<edgeDecor,int,dir>
instead.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);
Upvotes: 4
Reputation: 59496
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);
Upvotes: 1