代码之家  ›  专栏  ›  技术社区  ›  Niel de Wet

什么使这个“声明者无效”?C++

  •  5
  • Niel de Wet  · 技术社区  · 15 年前

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

    20 template<class edgeDecor, class vertexDecor, bool dir>
    21 class 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 };
    

    海合会说:

    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
    

    我知道这可能是另一个没用的问题,但我会感谢你的帮助。

    3 回复  |  直到 15 年前
        1
  •  1
  •   Agnel Kurian    15 年前

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

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

    …你可能需要说:

    Vertex<edgeDecor,int,dir> v = new Vertex<edgeDecor,int,dir>(INT_MAX);
    
        2
  •  4
  •   Igor Zevaka    15 年前

    可能需要

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

    因为您正在声明 Vertex . typename 关键字仅在模板参数列表中有效。

    谢谢 阿贝 奥蒂斯 指出 keyword 在模板参数列表之外。

    在对代码进行了另一番研究之后,我想到了许多其他的事情:

    1. 正如 迈克·丁斯代尔 此处缺少模板参数: new Vertex(INT_MAX); . 尝试 Vertex<edgeDecor,int,dir> 相反。
    2. 您正在将指针分配给类实例。如果您在堆栈上创建它,它应该如下所示:

      顶点v(int_max);

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

    Vertex<edgeDecor,int,dir>* v = new Vertex<edgeDecor,int,dir>(INT_MAX);
    
        3
  •  0
  •   Matthieu M.    15 年前

    如前所述,这是一个错位的问题 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;
    }
    

    没有必要 类别名 因为没有歧义,编译器知道 类名 一定是这里的类型。

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

    我们需要消除歧义,因为编译器不知道 Foo 符号将是类型、方法或属性。确实,如果 T == int 此代码是错误的,因为 代表一个 static 属性而不是 struct !

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

    在这里 类别名 不需要:因为编译器知道模板参数列表中的所有类型,所以它可以为 MyClass<int> MyClass<float> 至于常规类,它知道每个实例化的内部(尤其是每个符号所表示的)。

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

    我们再次需要 类别名 因为 是一种类型,编译器需要知道它。

    如果你不明白,别担心。这个 类别名 template 关键字有时会在泛型代码中的一些不寻常的地方出现:只要等待编译器错误开始,您很快就会记住错误的种类并在眨眼间纠正它们。