Niel de Wet
Niel de Wet

Reputation: 8408

What makes this "declarator invalid"? C++

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

Answers (3)

Matthieu M.
Matthieu M.

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

Igor Zevaka
Igor Zevaka

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:

  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);

Upvotes: 4

Agnel Kurian
Agnel Kurian

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

Related Questions