2010-03-23 18 views
5

Tengo la plantilla Vertex en vertex.h. Desde mi graph.h:¿Qué hace que este "declarador no sea válido"? C++

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

que utilizo en mi plantilla de gráfico.

Utilicé la plantilla Vertex con éxito en todo mi gráfico, devuelvo punteros a Vértices, etc. Ahora, por primera vez, intento declarar y crear instancias de un objeto Vertex, y gcc me dice que mi 'declarante' es 'inválido'. ¿Cómo puede ser esto?

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

y GCC está diciendo:

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 

Sé que esto es probablemente otra pregunta noob, pero podrá apreciar ninguna ayuda.

+0

Probablemente no está relacionado con este problema, pero ¿está seguro de que quiere que "= new Vertex (INT_MAX)"? ¿Quizás quiso decir "vertex" sin capitalizar (que supongo que es un typedef)? También Vertex <...> realmente tiene un ctor tomando un puntero vértice/vértice? –

Respuesta

1

Igor es correcto. En cuanto al siguiente error:

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

... es probable que tenga que decir:

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

Eso lo resolvió. Gracias. –

4

probable que necesite ser

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

debido a que se está declarando una instancia de Vertex. La palabra clave typename solo es válida dentro de la lista de parámetros de la plantilla.

Gracias Abhay y Outis por señalar usos válidos de keyword fuera de la lista de parámetros de plantilla.

Después de tener otra mirada en el código de una serie de otras cosas vienen a la mente:

  1. Como ha señalado Mike Dinsdale se echa en falta los parámetros de plantilla aquí: new Vertex(INT_MAX);. Pruebe Vertex<edgeDecor,int,dir> en su lugar.
  2. Está asignando un puntero a una instancia de clase. Si lo está creando en la pila, debería ser algo como esto:

    Vertex v (INT_MAX);

Si se crea en el montón v debe ser un tipo de puntero:

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

"typename keyword solo es válido dentro de la lista de parámetros de la plantilla", no lo creo. Para los nombres dependientes de la plantilla, la mayoría de los compiladores requieren que especifique * typename *. – Abhay

+0

Nombres dependientes de RE: lee http://pages.cs.wisc.edu/~driscoll/typename.html. En el caso del OP, 'Vertex ' no es un nombre de tipo dependiente, por lo que 'typename' no es válido. – outis

+0

Sin el "nombre de tipo" gcc palabra clave da: graph.h: 88: error: se esperaba tipo especificador antes de Vertex que me hace pensar es necesaria "nombre de tipo" aquí para indicar al compilador que me refiero a un tipo. –

0

Como se ha dicho, se trata de un problema de fuera de lugar typename primero.

Algunos ejemplos:

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

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

Uso de MyClass:

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

No hay necesidad de typename porque no hay ambigüedad, el compilador sabe MyClass Tiene que haber un tipo aquí.

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

Tenemos que eliminar la ambigüedad porque el compilador no sabe de antemano si el símbolo Foo será un tipo, un método o un atributo. De hecho, si T == int este código es erróneo ya que Foo representaría un atributo static en lugar de ser un struct!

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

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

Aquí typename no es necesaria: ya que el compilador conoce todos los tipos en la lista de parámetros de plantilla, se puede crear una instancia de la clase de plantilla para MyClass<int> y MyClass<float> y en cuanto a una clase regular sabe adentro hacia fuera de cada instanciación (y, en particular, lo que cada símbolo representa).

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

Una vez más tenemos que typename porque Foo es un tipo y el compilador necesita saberlo.

Si realmente no lo entiendes, no te preocupes. Las palabras clave typename y template a veces aparecen en lugares inusuales en código genérico: simplemente espere a que comience el error del compilador, pronto memorizará el tipo de errores y los corregirá en un abrir y cerrar de ojos.