是什么让这个“宣告者无效”? C ++

时间:2010-03-23 05:12:01

标签: c++ templates gcc

我在vertex.h中有顶点模板。从我的graph.h:

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

我在我的Graph模板中使用。

我在整个Graph中成功使用了Vertex模板,返回指向Vertices的指针等。现在我第一次尝试声明并实例化一个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

我知道这可能是另一个noob问题,但我会感激任何帮助。

3 个答案:

答案 0 :(得分:4)

可能需要

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

因为您声明了Vertex的实例。 typename关键字仅在模板参数列表中有效。

感谢 Abhay outis 指出模板参数列表之外的keyword的有效使用。

在再看一下代码之后,我想到了其他一些事情:

  1. 正如 Mike Dinsdale 指出的那样,您在这里缺少模板参数:new Vertex(INT_MAX);。请改为Vertex<edgeDecor,int,dir>
  2. 您正在指定一个类实例的指针。如果你在堆栈上创建它应该是这样的:

    Vertex v(INT_MAX);

  3. 如果在堆v上创建必须是指针类型:

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

答案 1 :(得分:1)

伊戈尔是对的。至于以下错误:

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

......你可能需要说:

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

答案 2 :(得分:0)

如上所述,这是首先错位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<int>MyClass<float>的模板类以及常规类知道每个实例的内部 - (特别是每个符号代表什么)。

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

我们需要typename,因为Foo是一种类型,编译器需要知道它。

如果你真的没有,请不要担心。 typenametemplate关键字有时会在通用代码中的不寻常位置蔓延:只需等待编译器错误开始,您很快就会记住这类错误并在眨眼中纠正它们。 / p>