У меня есть шаблон Vertex в vertex.h. От моего graph.h:
20 template<class edgeDecor, class vertexDecor, bool dir>
21 class Vertex;
который я использую в своем шаблоне Graph.
Я использовал шаблон Vertex успешно всюду по моему Графику, возвратите указатели на Вершины и т.д. Теперь впервые я пытаюсь объявить и инстанцировать объекта Вершины, и gcc говорит мне, что мой 'оператор объявления' 'недопустим'. Как это может быть?
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 };
И gcc говорит:
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
Я знаю, что это - вероятно, другой вопрос о новичке, но я буду ценить любую справку.
Игорь прав. Что касается следующей ошибки:
graph.h:88: error: expected type-specifier before ‘Vertex’
... вам, вероятно, нужно сказать:
Vertex<edgeDecor,int,dir> v = new Vertex<edgeDecor,int,dir>(INT_MAX);
Вероятно, необходимо
Vertex<edgeDecor,int,dir> v = new Vertex(INT_MAX);
, потому что вы объявляете экземпляр Vertex
. ключевое слово typename
допустимо только внутри списка параметров шаблона.
Спасибо Абхаю и outis за указание на допустимые варианты использования ключевого слова
вне списка параметров шаблона.
После повторного просмотра кода на ум приходит ряд других вещей:
новая вершина (INT_MAX);
. Попробуйте вместо этого Vertex
. Вы назначаете указатель на экземпляр класса. Если вы создаете его в стеке, это должно быть примерно так:
Vertex v (INT_MAX);
При создании в куче v
должен иметь тип указателя:
Vertex<edgeDecor,int,dir>* v = new Vertex<edgeDecor,int,dir>(INT_MAX);
Как уже говорилось, это проблема неуместного typename
в первую очередь.
Некоторые примеры:
template <class T>
struct MyClass
{
struct Foo { static int MBar; };
};
template <>
struct MyClass<int> { static int Foo; };
Использование MyClass
:
template <class T>
void useMyClass(T t)
{
MyClass<T> c;
}
Нет необходимости в typename
, потому что нет двусмысленности, компилятор знает, что MyClass
получил быть здесь типажем.
template <class T>
void useFoo(T t)
{
typename MyClass<T>::Foo f;
}
Нам необходимо устранить неоднозначность, поскольку компилятор заранее не знает, будет ли символ Foo
типом, методом или атрибутом. Действительно, если T == int
, этот код ошибочен, поскольку Foo
будет представлять атрибут static
вместо struct
!
void useFoo(int t)
{
int f = MyClass<int>::Foo;
}
void useFoo(float t)
{
float f = MyClass<float>::Foo::MBar;
}
Здесь typename
не требуется: поскольку компилятор знает все типы в списке параметров шаблона, он может создать экземпляр класса шаблона для MyClass
и MyClass
, а что касается обычного класса, он знает внутреннюю сторону каждого экземпляра (и, в частности, что представляет каждый символ).
template <class T>
void useBar(T t)
{
int i = typename MyClass<T>::Foo::MBar;
}
Еще раз нам нужно typename
, потому что Foo
- это тип, и компилятор должен его знать.
Если вы этого не понимаете, не волнуйтесь. Ключевые слова typename
и template
иногда закрадываются в необычных местах общего кода: просто подождите, пока не начнется ошибка компилятора, вы скоро запомните тип ошибок и исправите их в подмигивание.